TensorFlow深度学习实战(20)——自组织映射详解
TensorFlow深度学习实战(20)——自组织映射详解
- 0. 前言
- 1. 自组织映射原理
- 2. 自组织映射的优缺点
- 3. 使用自组织映射实现颜色映射
- 小结
- 系列链接
0. 前言
自组织映射 (Self-Organizing Map
, SOM
) 是一种无监督学习算法,主要用于高维数据的降维、可视化和聚类分析,广泛应用于数据挖掘、模式识别、图像处理等领域。
1. 自组织映射原理
K-means 和主成分分析 (Principal Component Analysis, PCA) 都可以对输入数据进行聚类,但它们不保持拓扑关系。在本节中,我们将介绍自组织映射 (Self-Organizing Map
, SOM
),也称 Kohonen
网络,或 WTU
(Winner-Take-All Unit
),由 Teuvo Kohonen
于 1982
年提出,这类方法能够保持拓扑关系。SOM
是一种非常特殊的神经网络,受到人脑一个独特特征的启发,在人类大脑中,不同的感官输入以拓扑顺序的方式表示。与其他神经网络不同,神经元之间不是通过权重连接在一起,而是相互影响学习。SOM
最重要的是,神经元以拓扑方式表示学习到的输入。
在 SOM
中,神经元通常放置在( 1D
或 2D
)网格的节点上。虽然也可以使用更高维度,但在实践中很少使用。网格中的每个神经元通过权重矩阵连接到所有输入单元。下图展示了一个具有 6 × 8
(48
个)神经元和 5
个输入的 SOM
。在这种情况下,每个神经元将有 5
个元素,从而形成一个大小为 48 × 5
的权重矩阵:
自组织映射 (Self-Organizing Map
, SOM
) 通过竞争学习来学习,可以视为 PCA
的非线性推广,因此,像主成分分析 (Principal Component Analysis, PCA) 一样,也可以用于降维。
为了实现 SOM
,首先需要了解它的工作原理。第一步是将网络的权重初始化为随机值或从输入中随机抽样。每个占据网格空间的神经元将被分配特定的位置,与输入距离最小的神经元称为获胜神经元 (Best Matching Unit
, BMU
),通过测量所有神经元的权重向量 W W W 与输入向量 X X X 之间的距离实现:
d j = ∑ i = 1 N ( W i j − X i ) 2 d_j=\sqrt{\sum_{i=1}^N(W_{ij}-X_i)^2} dj=i=1∑N(Wij−Xi)2
其中, d j d_j dj 是神经元 j j j 的权重与输入 X X X 之间的距离,具有最低 d d d 值的神经元是获胜神经元。
接下来,调整胜者神经元及其邻近神经元的权重,以确保如果下一次输入相同,同一神经元仍然是获胜神经元。
为了决定哪些邻近神经元需要修改,网络使用邻域函数 ∨ ) ( r ) \vee )(r) ∨)(r),通常使用以下邻域函数:
∨ ( r ) = e − d 2 2 σ 2 \vee (r)=e^{-\frac {d^2}{2\sigma^2}} ∨(r)=e−2σ2d2
其中, σ \sigma σ 是神经元影响范围的时间依赖半径, d d d 是它与获胜神经元的距离,函数图像如下所示。
邻域函数的另一个重要特性是其半径会随着时间减少。因此,在开始时,许多邻近神经元的权重会修改,但随着网络的学习,最终只有少数神经元的权重(有时是一个或没有)在学习过程中修改。
权重的变化根据以下方程:
d W = η ∧ ( X − W ) dW=\eta \wedge(X-W) dW=η∧(X−W)
对所有输入重复迭代以上过程。随着迭代的进行,根据迭代次数逐渐降低学习率和半径。
2. 自组织映射的优缺点
自组织映射 (Self-Organizing Map
, SOM
) 的计算成本较高,因此对于较大的数据集并不实用。但它们易于理解,并且能够很好地发现输入数据之间的相似性。因此,SOM
被广泛应用于图像分割和在自然语言处理中确定词汇相似性映射。
具体而言,SOM
具有以下优势
- 无监督学习:
SOM
是一种无监督学习算法,可以在没有标签的情况下进行数据分析和模式识别 - 能够处理高维数据:
SOM
能够将高维数据映射到低维空间,从而帮助我们更好地理解和可视化高维数据 - 数据聚类与模式识别:
SOM
可以将相似的数据点映射到网格中相邻的位置,从而实现数据的聚类。由于SOM
保持了输入数据的拓扑结构,相似的输入数据会被映射到网格中相邻的节点,这使得它在模式识别、异常检测等任务中有着较好的表现 - 自适应性:
SOM
在训练过程中能够根据输入数据的分布情况自适应地调整模型结构,能够有效地识别出数据中的重要模式
SOM
的缺点如下:
- 计算复杂度高:
SOM
的训练过程需要对每一个输入数据点计算与所有神经元的距离,这使得它在大规模数据集上训练时计算量较大,训练时间较长,尤其是对于高维数据 - 对初始化敏感:
SOM
的性能对初始化有一定的依赖,如果初始化的权重分布不合理,可能导致训练结果不理想 - 容易陷入局部最优:
SOM
的训练算法具有局部更新的特性,容易陷入局部最优解,尤其是在数据特征复杂或者维度较高时,可能会导致学习过程无法收敛到最优解 - 对噪声敏感:
SOM
对数据中的噪声较为敏感,噪声数据可能会导致训练结果失真,从而影响映射效果
3. 使用自组织映射实现颜色映射
自组织映射 (Self-Organizing Map
, SOM
) 生成的输入空间特征图具有一些有趣的属性:
- 特征图提供了输入空间的良好表示,这一属性可以用于向量量化,从而可以将一个连续的输入空间用SOM表示为一个离散的输出空间
- 特征图是拓扑有序的,即输出网格中神经元的空间位置对应于输入的特定特征
- 特征图还反映了输入空间的统计分布;具有最多输入样本的区域在特征图中占据较大的面积
SOM
的这些特性使其具有许多有趣的应用。在本节中,使用 SOM
将给定的红 (Red
, R
)、绿 (Green
, G
) 和蓝 (Blue
, B
) 像素值聚类到相应的颜色图中。
(1) 首先导入所需的模块:
import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt
import time
(2) 定义 WTU
类。__init__
函数初始化了 SOM
的各种超参数,包括 2D
网格的维度 (m, n)
、输入特征的数量 dim
、邻域半径 sigma
、初始权重以及拓扑信息:
# Define the Winner Take All units
class WTU(object):def __init__(self, m, n, dim, num_iterations, eta = 0.5, sigma = None):self._m = mself._n = nself._neighbourhood = []self._topography = []self._num_iterations = int(num_iterations) self._learned = Falseself.dim = dimself.eta = float(eta)if sigma is None:sigma = max(m,n)/2.0 # Constant radiuselse:sigma = float(sigma)self.sigma = sigmaprint('Network created with dimensions',m,n)# Weight Matrix and the topography of neuronsself._W = tf.random.normal([m*n, dim], seed = 0)self._topography = np.array(list(self._neuron_location(m, n)))
WTU
类最重要的函数是 training()
函数,使用 Kohonen
算法找到获胜神经元,并根据邻域函数更新权重:
def training(self,x, i):m = self._mn= self._n # Finding the Winner and its locationd = tf.sqrt(tf.reduce_sum(tf.pow(self._W - tf.stack([x for i in range(m*n)]),2),1))self.WTU_idx = tf.argmin(d,0)slice_start = tf.pad(tf.reshape(self.WTU_idx, [1]),np.array([[0,1]]))self.WTU_loc = tf.reshape(tf.slice(self._topography, slice_start,[1,2]), [2])# Change learning rate and radius as a function of iterationslearning_rate = 1 - i/self._num_iterations_eta_new = self.eta * learning_rate_sigma_new = self.sigma * learning_rate# Calculating Neighbourhood functiondistance_square = tf.reduce_sum(tf.pow(tf.subtract(self._topography, tf.stack([self.WTU_loc for i in range(m * n)])), 2), 1)neighbourhood_func = tf.exp(tf.negative(tf.math.divide(tf.cast(distance_square, "float32"), tf.pow(_sigma_new, 2))))# multiply learning rate with neighbourhood funceta_into_Gamma = tf.multiply(_eta_new, neighbourhood_func)# Shape it so that it can be multiplied to calculate dWweight_multiplier = tf.stack([tf.tile(tf.slice(eta_into_Gamma, np.array([i]), np.array([1])), [self.dim])for i in range(m * n)])delta_W = tf.multiply(weight_multiplier,tf.subtract(tf.stack([x for i in range(m * n)]),self._W))new_W = self._W + delta_Wself._W = new_W
fit()
函数是一个辅助函数,调用 training()
函数并存储质心网格以便于检索:
def fit(self, X):for i in range(self._num_iterations):for x in X:self.training(x,i)# Store a centroid grid for easy retrievalcentroid_grid = [[] for i in range(self._m)]self._Wts = list(self._W)self._locations = list(self._topography)for i, loc in enumerate(self._locations):centroid_grid[loc[0]].append(self._Wts[i])self._centroid_grid = centroid_gridself._learned = True
然后,定义一些辅助函数用于找到获胜神经元并生成 2D
神经元网格,以及一个将输入向量映射到 2D
网格中相应神经元的函数:
def winner(self, x):idx = self.WTU_idx,self.WTU_locreturn idxdef _neuron_location(self,m,n):for i in range(m):for j in range(n):yield np.array([i,j])def get_centroids(self):if not self._learned:raise ValueError("SOM not trained yet")return self._centroid_griddef map_vects(self, X):if not self._learned:raise ValueError("SOM not trained yet")to_return = []for vect in X:min_index = min([i for i in range(len(self._Wts))],key=lambda x: np.linalg.norm(vect - self._Wts[x]))to_return.append(self._locations[min_index])return to_return
(3) 定义函数 normalize()
用于对输入数据进行归一化:
def normalize(df):result = df.copy()for feature_name in df.columns:max_value = df[feature_name].max()min_value = df[feature_name].min()result[feature_name] = (df[feature_name] - min_value) / (max_value - min_value)return result.astype(np.float32)
(4) 读取数据 colors.csv
,对其进行归一化,数据包含不同颜色的红、绿和蓝通道值:
import pandas as pddf = pd.read_csv('colors.csv') # The last column of data file is a label
data = normalize(df[['R', 'G', 'B']]).values
name = df['Color-Name'].values
n_dim = len(df.columns) - 1# Data for Training
colors = data
color_names = name
(5) 接下来,创建 SOM
并进行训练:
t = time.time()
som = WTU(30, 30, n_dim, 400, sigma=10.0)
som.fit(colors)
s = time.time() - t
print(s)
# 3820.9206821918488
(6) fit()
函数运行时间稍长,训练完成后,查看模型训练结果:
# Get output grid
image_grid = som.get_centroids()# Map colours to their closest neurons
mapped = som.map_vects(colors)# Plot
plt.imshow(image_grid)
plt.title('Color Grid SOM')
for i, m in enumerate(mapped):plt.text(m[1], m[0], color_names[i], ha='center', va='center',bbox=dict(facecolor='white', alpha=0.5, lw=0))
plt.show()idx, loc = som.winner([0.5, 0.5, 0.5])
print(idx, loc)
可以在 2D
神经元网格中看到颜色映射:
可以看到,类似颜色的获胜神经元彼此靠近。
小结
自组织映射 (Self-Organizing Map
, SOM
) 是一种无监督学习算法,广泛用于数据的降维、聚类、模式识别等任务。它通过将高维数据映射到低维的网格上,使得相似的样本数据在网格中相邻。
系列链接
TensorFlow深度学习实战(1)——神经网络与模型训练过程详解
TensorFlow深度学习实战(2)——使用TensorFlow构建神经网络
TensorFlow深度学习实战(3)——深度学习中常用激活函数详解
TensorFlow深度学习实战(4)——正则化技术详解
TensorFlow深度学习实战(5)——神经网络性能优化技术详解
TensorFlow深度学习实战(6)——回归分析详解
TensorFlow深度学习实战(7)——分类任务详解
TensorFlow深度学习实战(8)——卷积神经网络
TensorFlow深度学习实战(9)——构建VGG模型实现图像分类
TensorFlow深度学习实战(10)——迁移学习详解
TensorFlow深度学习实战(11)——风格迁移详解
TensorFlow深度学习实战(12)——词嵌入技术详解
TensorFlow深度学习实战(13)——神经嵌入详解
TensorFlow深度学习实战(14)——循环神经网络详解
TensorFlow深度学习实战(15)——编码器-解码器架构
TensorFlow深度学习实战(16)——注意力机制详解
TensorFlow深度学习实战(17)——主成分分析详解
TensorFlow深度学习实战(18)——K-means 聚类详解
TensorFlow深度学习实战(19)——受限玻尔兹曼机