深度卷积神经网络在CPU上计算的加速

深度卷积神经网络在CPU上计算的加速


在利用MXNet对AlexNet简化模拟的实现过程中,由于机器没有独显,只能利用CPU进行计算。😦
结果发现,GPU上只用一两分钟跑完的5个epoch,CPU跑了十几分钟连一个epoch还没跑出来。这是代码能干得出来的事?欺负一个CPU算啥!CPU:“ 我太难了!”

原始读取数据函数

#通过Resize将图像高和宽扩大到AlexNet使用的图像高和宽224
def load_data_fashion_mnist(batch_size, resize=None, root=os.path.join('~', '.mxnet', 'datasets', 'fashion-mnist')):
    root = os.path.expanduser(root)
    transformer = []
    if resize:
        transformer += [gdata.vision.transforms.Resize(resize)]
    transformer += [gdata.vision.transforms.ToTensor()]
    transformer = gdata.vision.transforms.Compose(transformer)
    mnist_train = gdata.vision.FashionMNIST(root=root, train=True)
    mnist_test = gdata.vision.FashionMNIST(root=root, train=False)
    num_workers = 0 if sys.platform.startswith('win') else 4
    train_iter = gdata.DataLoader(mnist_train.transform_first(transformer), batch_size, shuffle=True, num_workers=num_workers)
    test_iter = gdata.DataLoader(mnist_test.transform_first(transformer), batch_size, shuffle=False, num_workers=num_workers)
    return train_iter, test_iter

函数优化

但这个函数有一个问题,运行代码的时候,内存占用异常的大。 这个函数将resize的过程放到了DataLoader函数之前,虽然速度可能有一些提升,但是内存占用的代价太大了。这样的话,CPU内存可能就爆掉了。
考虑将resize的步骤放到函数DataLoader里面。调用每一个batch的时候,将当前batch的数据resize。

首先定义一个DataLoader类,与mxnet.gluon.data.DataLoader不同的是,这个类使得读取数据时是读取一个batch后进行一次resize,而不是读取每个样本时就resize。

class DataLoader():
    def __init__(self, dataset, batch_size, shuffle, resize):
        self.dataset = dataset
        self.batch_size = batch_size
        self.shuffle = shuffle
        self.resize = resize
    def __iter__(self):
        data = self.dataset[:]
        X = data[0]
        y = nd.array(data[1])
        n = X.shape[0]
        if self.shuffle:
            idx = np.arange(n)
            np.random.shuffle(idx)
            X = nd.array(X.asnumpy()[idx])
            y = nd.array(y.asnumpy()[idx])
        for i in range(n//self.batch_size):
            batch_x = X[i*self.batch_size:(i+1)
                        * self.batch_size].astype('float32')
            if self.resize:
                new_data = nd.zeros(
                    (self.batch_size, self.resize, self.resize, batch_x.shape[3]))
                for j in range(self.batch_size):
                    new_data[j] = image.imresize(
                        batch_x[j], self.resize, self.resize)
                batch_x = new_data
            yield (nd.transpose(batch_x, (0, 3, 1, 2))/255, y.astype('float32')[i*self.batch_size:(i+1)*self.batch_size])
    def __len__(self):
        return len(self.dataset)//self.batch_size

然后重新定义读取数据的函数:

def load_data_fashion_mnist(batch_size, resize=None, root="~/.mxnet/datasets/fashion-mnist"):
    mnist_train = gluon.data.vision.FashionMNIST(root=root, train=True, transform=None)
    mnist_test = gluon.data.vision.FashionMNIST(root=root, train=False, transform=None)
    train_data = DataLoader(mnist_train, batch_size, shuffle=True, resize=resize)
    test_data = DataLoader(mnist_test, batch_size, shuffle=False, resize=resize)
    return train_data, test_data

Intel MKL-DNN加速CPU计算

函数优化了之后,跑了挺久时间,感觉还是跑不出。无奈的我继续查资料,发现了MKL-DNN,Intel推出的深度神经网络的数学核心库。使用之后,在以前的简单卷积神经网络上测试了一下,发现速度快了一倍,对深度卷积神经网络上的加速作用应该会更大!

有两种方法安装MKL-DNN,一种是直接下载预先编译好的自带MKL-DNN的MXNet,另一种是自行对MXNet进行编译。
我采用的是简单便捷的第一种方法,用pip先卸载了原有的MXNet,然后安装预先编译过的MXNet。安装完后就可以直接用了。

pip uninstall mxnet
pip install --pre mxnet-mkl

RUN!

之前程序没跑出来,我一直担心是不是程序出现了bug,所以一心想让程序跑出结果来的我决定给CPU一个证明她自己的机会,狠心按下了RUN,任CPU放飞自我。
洗漱、洗衣、游走,时间悄然流逝,机器升温,风扇轰鸣,笔记本侧立散热,CPU 飞速 运转,真心为她捏了一把汗 。

历时23min,CPU利用率峰值一度达到100%,洗完衣服的我发现终端惊现一行输出

epoch 1, loss 1.3076, train acc 0.511, test acc 0.737, time 1381.5 sec

我的CPU和我:😃
CPU不哭

我又消磨了20分钟,机器跑完了第2个epoch,并且loss的下降accuracy的升高表明,代码的确没有bug。限于时间问题和对CPU的关心,我决定不继续燃烧CPU了。

嗯,安心睡觉

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值