Python 2.7中1D Kohonen网络脚本运行缓慢原因排查求助
刚看到你的问题,把MATLAB里跑的顺顺的1D Kohonen网络移植到Python2.7后变慢确实挺头疼的,我之前也踩过类似的坑,大概率是这几个原因导致的,给你几个针对性的优化方向:
MATLAB的矩阵运算底层是优化过的BLAS/LAPACK,跑起来快得很,但Python里如果把MATLAB的向量化逻辑改成了纯Python嵌套循环(比如逐样本、逐神经元算距离、更新权重),速度会差好几个数量级。
举个例子,要是你在Python里写了这种代码:
# 糟糕的写法:纯Python循环计算距离 for sample in y: for idx in range(len(som_weights)): dist = np.linalg.norm(sample - som_weights[idx])
赶紧换成numpy的向量化实现,用广播一次性搞定所有计算:
# 优化写法:向量化计算所有样本到所有神经元的距离 # y形状:(样本数, 特征数),som_weights形状:(神经元数, 特征数) distances = np.sqrt(np.sum((y[:, np.newaxis] - som_weights)**2, axis=2))
这种底层用C实现的运算,速度会比纯Python循环快几十甚至上百倍。
Python2.7的numpy如果默认用的是纯Python版的BLAS,运算速度会比MATLAB慢很多。你可以跑一段代码看看配置:
import numpy as np np.__config__.show()
要是输出里看不到MKL或者OpenBLAS的字样,那得赶紧换个带优化库的numpy版本。比如用conda装:
conda install numpy=1.16.6 mkl
(因为Python2.7最高支持numpy1.16版本),或者编译带OpenBLAS的numpy,这一步能大幅提升矩阵运算的速度。
你提到从N=2开始递增训练不同规模的SOM,看看是不是每次训练新SOM时都做了很多重复工作?比如MATLAB里可能有预计算或者缓存,而Python里每次都重新初始化、从头计算所有步骤。
另外,邻域函数的实现也很关键,别用循环算每个神经元的邻域权重,换成向量化的方式:
# 向量化计算高斯邻域 winner_idx = 5 # 假设当前获胜神经元的索引 n_neurons = som_weights.shape[0] sigma = 1.0 neuron_indices = np.arange(n_neurons) neighborhood = np.exp(-(neuron_indices - winner_idx)**2 / (2 * sigma**2)) # 一次性更新所有神经元权重 som_weights += learning_rate * neighborhood[:, np.newaxis] * (current_sample - som_weights)
Python里有专门的SOM库,核心逻辑都是用C或者Cython写的,比你自己手写的纯Python代码快太多了。比如minisom(Python2.7支持旧版本):
# 先装旧版本:pip install minisom==2.2.7 from minisom import MiniSom # 初始化1D SOM:神经元数n_neurons,特征数是y的列数 som = MiniSom(n_neurons, 1, y.shape[1], sigma=1.0, learning_rate=0.5) som.random_weights_init(y) som.train_random(y, 1000) # 训练1000次迭代
还有somoclu支持GPU加速,要是你有GPU的话速度会更快,不过Python2.7的支持可能需要找对应版本。
Python2.7已经停止维护好几年了,它的循环性能比Python3.8+差不少,而且很多新的优化库都不再支持它。如果条件允许,建议升级到Python3.x,配合最新的numpy和SOM库,性能会有明显提升。要是必须用Python2.7,那前面的向量化和优化库的建议就更重要了。
最后,你可以用cProfile工具定位具体的慢代码块:
import cProfile cProfile.run('your_som_training_function()')
这样就能看到哪个函数占了最多时间,针对性优化就行。
内容的提问来源于stack exchange,提问作者Tendero

