You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

同结构模型在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 04:52:54