Skip to main content
 首页 » 编程设计

python之使用 Apache mxnet (gluon) 训练神经网络导致程序崩溃

2025年05月04日24oomusou

我正在尝试使用 Gluon API 在一组我想要分类的图像上使用 mxnet 训练卷积神经网络。但是,相同的网络和代码有时会针对相同的数据输出截然不同的结果,并且有时会因为某种原因而崩溃并拒绝运行。这是我的代码:

附加信息:

图像均为 131 x 131 像素大小,每类 176 张图像(2 类),每类 40 个测试。我很困惑为什么相同数据的相同程序有时应该提供输出但否则会崩溃。

导入

from __future__ import print_function 
import mxnet as mx 
import numpy as np 
from mxnet import nd, autograd, gluon 
import time 
mx.random.seed(1) 

设置上下文

ctx = mx.cpu() 

定义回调转换函数

def transform(data, label): 
    return nd.transpose(data.astype(np.float32), (2, 0, 1))/255, label 

在 o/p 层定义批量大小和节点数

batch_size = 5 
num_outputs = 2 

加载训练和测试数据

train_data = mx.gluon.data.DataLoader(mx.gluon.data.vision.ImageFolderDataset("/somepath/train", 0, transform), batch_size, shuffle=True) 
test_data = mx.gluon.data.DataLoader(mx.gluon.data.vision.ImageFolderDataset("/somepath/test", 0, transform), batch_size, shuffle=False) 

使用 gluon.nn 定义 CNN

neural_net = gluon.nn.Sequential() 
num_fc = 512 
 
with neural_net.name_scope(): 
    neural_net.add(gluon.nn.Conv2D(channels=20, kernel_size=5, activation='relu')) 
    neural_net.add(gluon.nn.MaxPool2D(pool_size=2, strides=2)) 
    neural_net.add(gluon.nn.Conv2D(channels=50, kernel_size=5, activation='relu')) 
    neural_net.add(gluon.nn.MaxPool2D(pool_size=2, strides=2)) 
    neural_net.add(gluon.nn.Flatten()) 
    neural_net.add(gluon.nn.Dense(num_fc, activation="relu")) 
    neural_net.add(gluon.nn.Dense(num_outputs)) 

初始化params、loss fn和trainer对象

neural_net.collect_params().initialize(mx.init.Xavier(magnitude=2.24), ctx=ctx) 
cross_entropy = gluon.loss.SoftmaxCrossEntropyLoss() 
trainer = gluon.Trainer(neural_net.collect_params(), 'adadelta') 

训练循环

total_time = 0 
for e in range(2): 
    tick = time.time() 
    for idx, (dpoint, label) in enumerate(train_data): 
        data = dpoint.as_in_context(ctx) 
        label = label.as_in_context(ctx) 
 
        with autograd.record(): 
            output = neural_net(data) 
            loss2 = cross_entropy(output, label) 
 
        loss2.backward()     
        trainer.step(data.shape[0]) 
    tock = time.time() 
    print("Epoch %s. Took %s seconds to train" %(e, tock-tick)) 
    total_time += tock-tick 
print("Total training time: %s" %(total_time)) 

测量精度

acc = mx.metric.Accuracy() 
for idx, (data, label) in enumerate(test_data): 
    something = data.as_in_context(ctx) 
    something_label = label.as_in_context(ctx) 
 
    output2 = neural_net(something) 
    predictions = nd.argmax(output2, axis=1) 
 
    acc.update(predictions, something_label) 
print(acc.get()[-1]) 

请您参考如下方法:

您的网络可能需要很长时间来计算数据的正向和反向传递。我追踪到感知到的对 acc.update 调用的无响应(比 neural_net(...) 晚一点)。深入研究此函数,我们正在等待 nd.asnumpy 解析。

混淆在于 MXNet NDArray 计算是异步的。所有训练前向/后向传递操作似乎立即解决,但实际上已添加到队列中进行处理。只有当数据被带回python进程(通过nd.asnumpy)时,你才需要等待相关操作完成。这在 acc.update 中首次发生。

另一种对某些代码块进行基准测试的方法是使用 mx.nd.waitall(),它会阻塞代码直到计算队列为空。将此添加到您的训练周期中,您会发现它花费的时间比最初出现的时间长得多。

使用 GPU 可能有助于解决这种明显的无响应问题。