同结构模型在Keras与Flux中训练效果差异过大求排查
Keras与Flux同结构CNN模型训练结果差异排查
教授提供包含301个晚型星系和301个早型星系的数据集,分别用Keras(Python)和Flux(Julia)构建同结构二分类CNN,但训练结果差异极大:Keras训练20轮后最终loss为0.0267,Flux训练30轮后loss为0.4082335f0,以下是相关代码及排查要点:
Keras(Python)模型代码
input_img = Input(shape=(128,128,3)) x = Conv2D(filters = 16, kernel_size= (3,3), strides = (1,1), activation='relu', padding = 'same')(input_img) x = MaxPooling2D((2,2),padding = 'same')(x) x = Conv2D(filters = 32, kernel_size= (3,3), strides = (1,1), activation='relu', padding = 'same')(x) x = MaxPooling2D((2,2),padding = 'same')(x) x = Conv2D(filters = 64, kernel_size= (3,3), strides = (1,1), activation='relu', padding = 'same')(x) x = MaxPooling2D((2,2),padding = 'same')(x) x = Flatten()(x) x = Dense(32, activation = 'relu')(x) x = Dropout(0.3)(x) x = Dense(16, activation = 'relu')(x) out = Dense(1, activation = 'sigmoid')(x) model = Model(inputs = input_img, outputs = out) model.compile(loss = 'binary_crossentropy', optimizer = 'adam', metrics = ['accuracy']) history = model.fit(X_train, Y_train, batch_size = 32, epochs = 20)
Flux(Julia)模型代码
model2 = Chain( Conv((3, 3), 3 => 16, relu, pad=SamePad(), stride=(1, 1)), MaxPool((2,2), pad=SamePad()), Conv((3, 3), 16 => 32, relu, pad=SamePad(), stride=(1, 1)), MaxPool((2,2), pad=SamePad()), Conv((3, 3), 32 => 64, relu, pad=SamePad(), stride=(1, 1)), MaxPool((2,2), pad=SamePad()), Flux.flatten, Dense(16384 => 32, relu), Dense(32 => 16, relu), Dense(16 => 1), sigmoid )
数据处理代码对比
Python数据处理代码
X1 = np.load('/home/luis/Descargas/cosmo-late.npy') X2 = np.load('/home/luis/Descargas/cosmo-early.npy') X = np.concatenate((X1,X2), axis = 0).astype(np.float32)/256.0 Y = np.zeros(X.shape[0]) Y[0:len(X1)] = 1 rand_ind = np.arange(0,X.shape[0]) np.random.shuffle(rand_ind) X = X[rand_ind] Y = Y[rand_ind] X_train = X[50:] Y_train = Y[50:] X_test = X[0:50] Y_test = Y[0:50]
Julia数据处理代码
X1 = npzread("./Descargas/cosmo-late.npy") X2 = npzread("./Descargas/cosmo-early.npy") X = cat(X1,X2,dims=1) X = Float32.(X)./256 Y = zeros(1,size(X)[1]) Y[1,1:length(X1[:,1,1,1])] .= 1 ind = collect(1:length(Y[1,:])) shuffle!(ind) X = X[ind,:,:,:] Y = Y[:,ind] X_train = X[51:length(X[:,1,1,1]),:,:,:] Y_train = Y[:,51:length(Y)] X_test = X[1:50,:,:,:] Y_test = Y[:,1:50] X_train = permutedims(X_train, (2, 3, 4, 1)) X_test = permutedims(X_test, (2, 3, 4, 1))
Flux训练代码
train_set = Flux.DataLoader((X_train, Y_train), batchsize=32) loss(x, y) = Flux.logitbinarycrossentropy(x, y) opt = Flux.setup(Adam(), model2) loss_history = Float32[] for epoch = 1:30 Flux.train!(model2, train_set, opt) do m,x,y err = loss(m(x), y) ChainRules.ignore_derivatives() do push!(loss_history, err) end return err end end
核心差异排查点
- Dropout层缺失:Keras模型包含
Dropout(0.3)正则化层,但Flux模型未添加对应层,会导致模型更容易过拟合,收敛速度变慢。 - 损失函数不匹配:Keras使用的
binary_crossentropy是针对sigmoid输出的交叉熵,而Flux的logitbinarycrossentropy要求输入是未经过sigmoid的logit值。当前Flux模型最后添加了sigmoid激活,导致损失计算逻辑错误,需改为Flux.binarycrossentropy或移除sigmoid层。 - 数据维度验证:确认Julia中
permutedims后的维度是否符合Flux要求(Flux Conv层默认输入格式为(height, width, channels, batch_size)),需核对原数据加载后的维度是否与Python端一致。 - 优化器参数对齐:Keras Adam默认参数为
learning_rate=0.001, beta_1=0.9, beta_2=0.999, epsilon=1e-07,需确认Flux Adam的默认参数是否一致,不一致则手动调整。 - 初始化策略差异:Keras与Flux的层初始化默认策略不同,可尝试手动设置一致的初始化方式(如He初始化)缩小初始差异。
内容的提问来源于stack exchange,提问作者Luis.Alberto
相关产品推荐
相关产品推荐

