在 Python 3.7 中,我的神经网络成本计算出现了问题。
当我第一次运行 compute_cost_nn
时,我得到了正确的成本 0.28762916516131887
,但在所有后续运行中,成本变为 0.3262751145707298
,这相当令人烦恼。
看起来问题出在我的 params
上;如果我在计算成本之前每次都重新加载它们,运行效果很好。但我无法在不重新运行整个脚本的情况下,使用不同的参数重新运行函数并获得正确的成本。
该神经网络有 400 个输入单元,一个包含 25 个单元的隐藏层,以及 10 个输出单元。
以下是输入数据:
data = loadmat("ex4data1.mat")y = data['y']X = data['X']X = np.c_[np.ones((X.shape[0], 1)), X]weights = loadmat("ex4weights.mat")Theta1 = weights['Theta1']Theta2 = weights['Theta2']params = np.r_[Theta1.ravel(), Theta2.ravel()]
矩阵形状:
>> X: (5000, 401)>> y: (5000, 1)>> Theta1: (25, 401)>> Theta2: (10, 26)>> params: (10285,)
成本函数如下:
def compute_cost_nn(params, input_layer_size, hidden_layer_size, num_labels, X, y, lambda_): m = len(y) # 从扁平化的 params 中检索 Theta1 和 Theta2 t1_items = (input_layer_size + 1) * hidden_layer_size Theta1 = params[0:t1_items].reshape( hidden_layer_size, input_layer_size+1 ) Theta2 = params[t1_items:].reshape( num_labels, hidden_layer_size+1 ) # 将 y 向量列(5000x1)转换为带有标签的 5000x10 矩阵,包含 0 和 1 y_mat = np.eye(num_labels)[(y-1).ravel(), :] # 前向传播 a1 = X z2 = a1 @ Theta1.T a2 = sigmoid(z2) a2 = np.c_[np.ones((m,1)), a2] z3 = a2 @ Theta2.T a3 = sigmoid(z3) # 计算成本 func = y_mat.T @ np.log(a3) + (1-y_mat).T @ np.log(1-a3) cost = func.trace() t1reg = (Theta1[:,1:].T @ Theta1[:,1:]).trace() t2reg = (Theta2[:,1:].T @ Theta2[:,1:]).trace() cost_r = -1/m * cost + lambda_/(2*m) * (t1reg + t2reg) # 梯度(不包括 Theta0) d3 = a3 - y_mat d2 = (d3 @ Theta2[:,1:]) * sigmoid_gradient(z2) #5000*25 Delta1 = d2.T @ a1 Delta2 = d3.T @ a2 Theta1_grad = 1/m * Delta1 Theta2_grad = 1/m * Delta2 # 梯度正则化 Theta1[:,1] = 0 Theta2[:,1] = 0 Theta1_grad = Theta1_grad + lambda_/m * Theta1 Theta2_grad = Theta2_grad + lambda_/m * Theta2 return cost_r, Theta1_grad, Theta2_grad
我通过运行以下代码获取成本:
compute_cost_nn(params, 400, 25, 10, X, y, 0)[0]
首次运行: 0.28762916516131887
然后: 0.3262751145707298
任何建议都将不胜感激 🙂
回答:
我没有用虚拟数据测试你的代码,但从快速浏览来看,你似乎是从 .mat
(MATLAB)文件中导入权重。MATLAB 以列优先顺序(也称为 Fortran 风格顺序)存储数组元素,而 Python 是行优先(C 风格顺序)。
因此,当你首次 ravel()
你的权重时,Numpy 会假设 C 风格顺序来扁平化数组。在你的函数中重塑扁平化的权重时也是如此。你可以在任一函数中添加 order 参数,因此:
params = np.r_[Theta1.ravel(order='F'), Theta2.ravel('F')]
应该能解决你的问题。
如果你之前从未遇到过行优先和列优先顺序,建议阅读一下相关内容:https://en.wikipedia.org/wiki/Row-_and_column-major_order