使用GlobalBestPSO训练神经网络时出现维度重塑ValueError的问题求助
GlobalBestPSO训练神经网络时出现维度重塑ValueError的问题求助
兄弟我懂你这头疼的问题!我之前也踩过PySwarms这个参数传递的坑,咱们一步步来拆解:
错误原因分析
你看到的560其实是这么来的:你设置了n_particles=10,每个粒子对应56个神经网络参数,PySwarms会把这10个粒子的参数堆叠成一个二维数组传给optimize_nn函数,总长度就是10×56=560。而你现在的函数直接把整个560长度的数组拿去reshape成(4,8),自然就会报维度不匹配的错误!
解决方案:修改目标函数以处理批量粒子参数
PySwarms的目标函数要求返回每个粒子对应的损失值,所以我们需要遍历每个粒子的参数,分别计算其对应的1-accuracy,最后返回一个长度等于粒子数的数组。
下面是修改后的完整代码,重点标注了修改的部分:
import numpy as np import pyswarms as ps import tensorflow as tf from sklearn.datasets import load_iris from sklearn.model_selection import train_test_split from tensorflow.keras.models import Sequential from tensorflow.keras.layers import Dense # Load Iris dataset iris = load_iris() X = iris.data y = iris.target # Normalize input data X = X.astype('float32') / np.max(X) # One-hot encode target labels y = tf.keras.utils.to_categorical(y) # Split the dataset into train and test sets X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.80, random_state=11) # Define bounds for the particles in PSO param_bounds = ([-1] * 56, [1] * 56) # 56 parameters for the weights # 修改后的目标函数:处理批量粒子参数 def optimize_nn(params): # params是形状为(n_particles, dimensions)的二维数组 n_particles = params.shape[0] losses = [] for i in range(n_particles): single_params = params[i] # 取出单个粒子的56维参数 model = Sequential() model.add(Dense(8, input_shape=(4,), activation='relu')) model.add(Dense(3, activation='sigmoid')) model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy']) # Set the weights for each layer separately first_layer_weights = single_params[:32].reshape((4, 8)) second_layer_weights = single_params[32:].reshape((8, 3)) model.layers[0].set_weights([first_layer_weights, np.zeros(8)]) model.layers[1].set_weights([second_layer_weights, np.zeros(3)]) _, accuracy = model.evaluate(X_train, y_train, verbose=0) losses.append(1 - accuracy) # 收集每个粒子的损失值 return np.array(losses) # 返回所有粒子的损失数组 # Create a PSO optimizer optimizer = ps.single.GlobalBestPSO(n_particles=10, dimensions=56, options={'c1': 0.5, 'c2': 0.3, 'w': 0.9}) # Perform optimization best_cost, best_params = optimizer.optimize(optimize_nn, iters=50) # Create a new neural network model best_model = Sequential() best_model.add(Dense(8, input_shape=(4,), activation='relu')) best_model.add(Dense(3, activation='sigmoid')) # Set the best weights found by PSO first_layer_weights = best_params[:32].reshape((4, 8)) second_layer_weights = best_params[32:].reshape((8, 3)) best_model.layers[0].set_weights([first_layer_weights, np.zeros(8)]) best_model.layers[1].set_weights([second_layer_weights, np.zeros(3)]) # Compile the best model best_model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy']) # Evaluate the best model on the test set loss, accuracy = best_model.evaluate(X_test, y_test, verbose=0) print("Test set accuracy: {:.2f}%".format(accuracy * 100))
关于官方示例的问题
你提到官方示例也有同样问题,大概率是因为PySwarms的版本更新导致API变化——旧版本可能是向目标函数传递单个粒子的参数,而新版本默认传递所有粒子的参数矩阵。按照上面的修改方式调整官方示例的目标函数,就能解决问题啦。
备注:内容来源于stack exchange,提问作者Abdallah Abu Samaha
相关产品推荐
相关产品推荐

