2019-07-17 11:09:19 u012350430 阅读数 2232
  • Fast.ai 深度学习实战课程「中文字幕」

    本课程由 Jeremy Howard 教授开设,共8节。目的是让大家在不需要深入研究高水平数学问题的情况下,学习如何建立先进的深度学习模型。 Jeremy Howard 教授结合自己参加 Kaggle 大赛并夺魁的经验认为,传统学院派的教学方式对于大多数学习者来说已经不适用,应该以问题为引导,以实践为驱动,尽快切入到核心理论和核心工具的使用上,掌握深度学习优模型的构建方法。

    17513 人正在学习 去看看 AI100讲师

写在前面

最近在一个自然语言处理方面的项目,选用的深度学习模型有两个,一个是CNN+LSTM模型,一个是GRU模型,这两个模型在GPU服务器上训练好了,然后需要使用Java调用这两个模型,CNN+LSTM使用TensorFlow写的,GRU是用Keras写的,所以需要用Java部署TensorFlow和Keras训练好的深度学习模型。关于这方面的内容网上并不是很多,我也是费了很多周折才完成任务的,这里来总结一下具体有哪些方法可以用,这些方法又有哪些缺陷,以供大家学习交流。

一、使用Java深度学习框架直接部署

(1)使用TensorFlow Java API部署TensorFlow模型

如果我们使用的是TensorFlow训练的模型,那么我们就可以直接使用Java中的TensorFlow API调用模型。这里需要注意的是我们得把训练好的模型保存为.pb格式的文件。具体代码如下:

# constant_graph = graph_util.convert_variables_to_constants(sess, sess.graph_def, output_node_names=["quest_out"])
# 写入序列化的 PB 文件
# with tf.gfile.FastGFile('/home/amax/zth/qa/new_model2_cpu.pb', mode='wb') as f:
#     f.write(constant_graph.SerializeToString())

然后我们需要在Java使用这个保存好的模型,在pom.xml中引入TensorFlow的依赖

<dependency>
            <groupId>org.tensorflow</groupId>
            <artifactId>tensorflow</artifactId>
            <version>1.11.0</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.tensorflow/libtensorflow_jni_gpu -->
        <dependency>
            <groupId>org.tensorflow</groupId>
            <artifactId>libtensorflow_jni_gpu</artifactId>
            <version>1.11.0</version>
        </dependency>

导包成功后,在Java中调用模型

graphDef = readAllBytes(new FileInputStream(new_model2_cpu.pb));
graph = new Graph();
graph.importGraphDef(graphDef);
session = new Session(graph);
Tensor result = session.runner()
                .feed("ori_quest_embedding", Tensor.create(wordVecInputSentence))//输入你自己的数据
                .feed("dropout", Tensor.create(1.0F))
                .fetch("quest_out") //和上面python保存模型时的output_node_names对应
                .run().get(0);
//这样就能得到模型的输出结果了

(2)使用Deeplearning4J Java API部署Keras模型

如果我们使用的是Keras训练的模型,那么你就可以选择Deeplearning4J 这个框架来调用模型。
第一步同样是使用Keras保存训练好的模型

filepath = "query_models"
 
checkpoint = ModelCheckpoint(filepath, monitor='val_acc', verbose=1, save_best_only=True)

callback_lists = [checkpoint]

model.fit(x, y, epochs=1,validation_split=0.2,callbacks=callback_lists)

然后同样是Java项目中pom.xml导入Deeplearning4J 依赖

  <dependency>      
    <groupId>org.deeplearning4j</groupId>      
    <artifactId>deeplearning4j-core</artifactId>
    <version>1.0.0-beta2</version>    
  </dependency>         
  <dependency>      
    <groupId>org.deeplearning4j</groupId>      
    <artifactId>deeplearning4j-modelimport</artifactId>      
    <version>1.0.0-beta2</version>    
  </dependency>                       

库导入成功后,直接使用Java调用保存好的模型

MultiLayerNetwork model = KerasModelImport.importKerasSequentialModelAndWeights(“query_models”);

这样模型就部署成功了,然后关于怎么使用模型这里就不多说了。
注意:这里需要注意的是Deeplearning4J 只支持部分深度学习模型,有些模型是不支持的,譬如我这里使用的GRU模型就不支持,运行上面代码会出现以下错误。明确指明不支持GRU模型
在这里插入图片描述
去Deeplearning4J 官网查询发现确实现在不支持GRU模型,以下是官网截图
在这里插入图片描述
所以如果你想使用Deeplearning4J 来部署训练好的模型,请先查看下是否支持你所使用的模型。

二、使用Python编写服务端

(1)使用socket实现进程间的通信

用python构建服务端,然后通过Java向服务端发送请求调用模型,第一种是使用socket实现进程中的通信,代码如下:

import socket
import sys
import threading
import json
import numpy as np
import jieba
import os
import numpy as np
import nltk
import keras
from keras.models import Sequential
from keras.layers import Dense
from keras.layers import Dropout
from keras.layers import LSTM,GRU,TimeDistributed
from keras.callbacks import ModelCheckpoint
from keras.utils import np_utils
from gensim.models.word2vec import Word2Vec
from keras.optimizers import Adam
from keras.models import load_model
import pickle
# nn=network.getNetWork()
# cnn = conv.main(False)
# 深度学习训练的神经网络,使用TensorFlow训练的神经网络模型,保存在文件中

w2v_model = Word2Vec.load("word2vec.w2v").wv
UNK = pickle.load(open('unk.pkl','rb'))
model = load_model('query_models')
a = np.zeros((1, 223,200))
model.predict(a)


def test_init(string):
    cut_list = jieba.lcut(string)
    x_test = np.zeros((1, 223,200))
    for i in range(223):
        x_test[0,i,:] = UNK
    for i in range(len(cut_list)):
        if cut_list[i] in w2v_model:
            x_test[0,i,:] = w2v_model.wv[cut_list[i]]   
    return x_test,len(cut_list)

string_list = list()
def query_complet(string):
    x_test,length = test_init(string)
    y = model.predict(x_test)
    if length>8:
        return
    word1 = w2v_model.wv.most_similar(positive=[y[0][length-1]], topn=2)[0][0]
    word2 = w2v_model.wv.most_similar(positive=[y[0][length-1]], topn=2)[1][0]
    if word1 == '?' or word1 == '?':
        string_list.append(string)
    else:
        new_str = string+word1
        query_complet(new_str)

    if word2 == '?' or word2 == '?':
        string_list.append(string)
    else:
        new_str = string+word2
        query_complet(new_str)
        
def new_query_complet(string):
    query_complet(string)
    return string_list

def main():
    # 创建服务器套接字
    serversocket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    # 设置一个端口
    port = 12345
    # 将套接字与本地主机和端口绑定
    serversocket.bind(("172.17.169.232",port))
    # 设置监听最大连接数
    serversocket.listen(5)
    # 获取本地服务器的连接信息
    myaddr = serversocket.getsockname()
    print("服务器地址:%s"%str(myaddr))
    # 循环等待接受客户端信息
    while True:
        # 获取一个客户端连接
        clientsocket,addr = serversocket.accept()
        print("连接地址:%s" % str(addr))
        try:
            t = ServerThreading(clientsocket)#为每一个请求开启一个处理线程
            t.start()
            pass
        except Exception as identifier:
            print(identifier)
            pass
        pass
    serversocket.close()
    pass

class ServerThreading(threading.Thread):
    # words = text2vec.load_lexicon()
    def __init__(self,clientsocket,recvsize=1024*1024,encoding="utf-8"):
        threading.Thread.__init__(self)
        self._socket = clientsocket
        self._recvsize = recvsize
        self._encoding = encoding
        pass

    def run(self):
        print("开启线程.....")
        try:
            #接受数据
            msg = ''
            while True:
                # 读取recvsize个字节
                rec = self._socket.recv(self._recvsize)
                # 解码
                msg += rec.decode(self._encoding)
                # 文本接受是否完毕,因为python socket不能自己判断接收数据是否完毕,
                # 所以需要自定义协议标志数据接受完毕
                if msg.strip().endswith('over'):
                    msg=msg[:-4]
                    break
            # 发送数据
            self._socket.send("啦啦啦啦".encode(self._encoding))
            pass
        except Exception as identifier:
            self._socket.send("500".encode(self._encoding))
            print(identifier)
            pass
        finally:
            self._socket.close() 
        print("任务结束.....")
        pass

//启动服务        
main()

Java客户端代码如下:

    public  void test2() throws IOException {
        JSONObject jsonObject = new JSONObject();
        String content = "医疗保险缴费需要";
        jsonObject.put("content", content);
        String str = jsonObject.toJSONString();
        // 访问服务进程的套接字
        Socket socket = null;
//        List<Question> questions = new ArrayList<>();
//        log.info("调用远程接口:host=>"+HOST+",port=>"+PORT);
        try {
            // 初始化套接字,设置访问服务的主机和进程端口号,HOST是访问python进程的主机名称,可以是IP地址或者域名,PORT是python进程绑定的端口号
            socket = new Socket("172.17.169.232",12345);
            // 获取输出流对象
            OutputStream os = socket.getOutputStream();
            PrintStream out = new PrintStream(os);
            // 发送内容
            out.print(str);
            // 告诉服务进程,内容发送完毕,可以开始处理
            out.print("over");
            // 获取服务进程的输入流
            InputStream is = socket.getInputStream();
            String text = IOUtils.toString(is);
            System.out.println(text);
    
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {if(socket!=null) socket.close();} catch (IOException e) {}
            System.out.println("远程接口调用结束.");
        }
    }

socket实现Python服务端确实比较简单,但是代码量比较大,没有前面Java直接部署训练好的模型简单。

(2)使用Python的Flask框架

Flask框架实现服务端,这个框架我是听我同学说的,因为他们公司就是使用这种方法部署深度学习模型的,不过我们项目当中没有用到,有兴趣的同学可以自己去了解一下这个Flask框架,这里不累述了。

总结

常用的方法基本上就上面这些了,以上方法各有各的优缺点,大家可以根据自己的项目需求自行选择合适的方法来部署训练好的深度学习模型,希望这篇博客可以帮到你们。

2019-10-22 16:47:03 u012108600 阅读数 539
  • Fast.ai 深度学习实战课程「中文字幕」

    本课程由 Jeremy Howard 教授开设,共8节。目的是让大家在不需要深入研究高水平数学问题的情况下,学习如何建立先进的深度学习模型。 Jeremy Howard 教授结合自己参加 Kaggle 大赛并夺魁的经验认为,传统学院派的教学方式对于大多数学习者来说已经不适用,应该以问题为引导,以实践为驱动,尽快切入到核心理论和核心工具的使用上,掌握深度学习优模型的构建方法。

    17513 人正在学习 去看看 AI100讲师

深度学习模型加速方法

1. 简介

深度学习(Deep Learning)因其计算复杂度或参数冗余,在一些场景和设备上限制了相应的模型部署,需要借助模型压缩、优化加速、异构计算等方法突破瓶颈。

  • 模型压缩算法能够有效降低参数冗余,从而减少存储占用、通信带宽和计算复杂度,有助于深度学习的应用部署,具体可划分为如下几种方法(后续重点介绍剪枝与量化):
  1. 线性或非线性量化:1/2bits, int8 和 fp16等;
  2. 结构或非结构剪枝:deep compression, channel pruning 和 network slimming等;
  3. 其他:权重矩阵的低秩分解,知识蒸馏与网络结构简化(squeeze-net, mobile-net, shuffle-net)等;
  • 模型优化加速能够提升网络的计算效率,具体包括:
  1. Op-level的快速算法:FFT Conv2d (7x7, 9x9), Winograd Conv2d (3x3, 5x5) 等;
  2. Layer-level的快速算法:Sparse-block net [1] 等;
  3. 优化工具与库:TensorRT (Nvidia), Tensor Comprehension (Facebook) 和 Distiller (Intel) 等;
  • 异构计算方法借助协处理硬件引擎(通常是PCIE加速卡、ASIC加速芯片或加速器IP),完成深度学习模型在数据中心或边缘计算领域的实际部署,包括GPU、FPGA或DSA (Domain Specific Architecture) ASIC等。异构加速硬件可以选择定制方案,通常能效、性能会更高,目前市面上流行的AI芯片或加速器可参考 [2]。显然,硬件性能提升带来的加速效果非常直观,例如2080ti与1080ti的比较(以复杂的PyramidBox人脸检测算法为例,约提速36%);另外,针对数据中心部署应用,通常选择通用方案,会有完善的生态支持,例如NVIDIA的CUDA,或者Xilinx的xDNN。

 

2. TensorRT基础

TensorRT是NVIDIA推出的深度学习优化加速工具,采用的原理如下图所示,具体可参考[3] [4]:

TensorRT能够优化重构由不同深度学习框架训练的深度学习模型

  • 对于Caffe与TensorFlow训练的模型,若包含的操作都是TensorRT支持的,则可以直接由TensorRT优化重构;
  • 对于MXnet, PyTorch或其他框架训练的模型,若包含的操作都是TensorRT支持的,可以采用TensorRT API重建网络结构,并间接优化重构;
  • 其他框架训练的模型,转换为ONNX中间格式后,若包含的操作是TensorRT支持的,可采用TensorRT-ONNX接口予以优化 [27];
  • 若训练的网络模型包含TensorRT不支持的操作:
  1. TensorFlow模型可通过tf.contrib.tensorrt转换,其中不支持的操作会保留为TensorFlow计算节点;MXNet也支持类似的计算图转换方式;
  2. 不支持的操作可通过Plugin API实现自定义并添加进TensorRT计算图,例如Faster Transformer的自定义扩展 [26];
  3. 将深度网络划分为两个部分,一部分包含的操作都是TensorRT支持的,可以转换为TensorRT计算图。另一部则采用其他框架实现,如MXnet或PyTorch;
  • TensorRT的int8量化需要校准(calibration)数据集,一般至少包含1000个样本(反映真实应用场景),且要求GPU的计算功能集sm >= 6.1;

在1080ti平台上,基于TensorRT4.0.1,Resnet101-v2的优化加速效果如下:

Network Precision Framework / GPU: 1080ti (P) Avg. Time (Batch=8, unit: ms) Top1 Val. Acc. (ImageNet-1k)
Resnet101 fp32 TensorFlow 36.7 0.7612
Resnet101 fp32 MXnet 25.8 0.7612
Resnet101 fp32 TRT4.0.1 19.3 0.7612
Resnet101 int8 TRT4.0.1 9 0.7574

在1080ti/2080ti平台上,基于TensorRT5.1.5,Resnet101-v1d的float16加速效果如下(由于2080ti包含Tensor Core,因此float16加速效果较为明显):

网络 平台 数值精度 Batch=8 Batch=4 Batch=2 Batch=1
Resnet101-v1d 1080ti float32 19.4ms 12.4ms 8.4ms 7.4ms
float16 28.2ms 16.9ms 10.9ms 8.1ms
int8 8.1ms 6.7ms 4.6ms 4ms
2080ti float32 16.6ms 10.8ms 8.0ms 7.2ms
float16 14.6ms 9.6ms 5.5ms 4.3ms
int8 7.2ms 3.8ms 3.0ms 2.6ms

3. 网络剪枝

深度学习模型因其稀疏性过拟合倾向,可以被裁剪为结构精简的网络模型,具体包括结构性剪枝与非结构性剪枝:

  • 非结构剪枝:通常是连接级、细粒度的剪枝方法,精度相对较高,但依赖于特定算法库或硬件平台的支持,如Deep Compression [5], Sparse-Winograd [6] 算法等;
  • 结构剪枝:是filter级或layer级、粗粒度的剪枝方法,精度相对较低,但剪枝策略更为有效,不需要特定算法库或硬件平台的支持,能够直接在成熟深度学习框架上运行。如局部方式的、通过layer by layer方式的、最小化输出FM重建误差的Channel Pruning [7], ThiNet [8], Discrimination-aware Channel Pruning [9];全局方式的、通过训练期间对BN层Gamma系数施加L1正则约束的Network Slimming [10];全局方式的、按Taylor准则对Filter作重要性排序的Neuron Pruning [11];全局方式的、可动态重新更新pruned filters参数的剪枝方法 [12];基于GAN思想的GAL方法 [24],可裁剪包括Channel, Branch或Block等在内的异质结构;借助Geometric Median确定卷积滤波器冗余性的剪枝策略 [28];

Channel Pruning为例,结构剪枝的规整操作如下图所示,可兼容现有的、成熟的深度学习框架:

4. 模型量化

模型量化是指权重或激活输出可以被聚类到一些离散、低精度(reduced precision)的数值点上,通常依赖于特定算法库或硬件平台的支持:

  • 二值化网络:XNORnet [13], ABCnet with Multiple Binary Bases [14], Bin-net with High-Order Residual Quantization [15], Bi-Real Net [16];
  • 三值化网络:Ternary weight networks [17], Trained Ternary Quantization [18];
  • W1-A8 或 W2-A8量化: Learning Symmetric Quantization [19];
  • INT8量化:TensorFlow-lite [20], TensorRT [21], Quantization Interval Learning [25];
  • 其他(非线性):Intel INQ [22], log-net, CNNPack [23] 等;

若模型压缩之后,推理精度存在较大损失,可以通过fine-tuning予以恢复,并在训练过程中结合适当的Tricks,例如Label Smoothing、Mix-up、Knowledge Distillation、Focal Loss等。 此外,模型压缩、优化加速策略可以联合使用,进而可获得更为极致的压缩比与加速比。例如结合Network Slimming与TensorRT int8优化,在1080ti Pascal平台上,Resnet101-v1d在压缩比为1.4倍时(Size=170MB->121MB,FLOPS=16.14G->11.01G),经TensorRT int8量化之后,推理耗时仅为7.4ms(Batch size=8)。

其中知识蒸馏(Knowledge Distillation)相关的讨论可参考:

https://blog.csdn.net/nature553863/article/details/80568658

 

References

[1] https://arxiv.org/abs/1801.02108, Github: https://github.com/uber/sbnet

[2] https://basicmi.github.io/Deep-Learning-Processor-List/

[3] https://devblogs.nvidia.com/tensorrt-3-faster-tensorflow-inference/

[4] https://devblogs.nvidia.com/int8-inference-autonomous-vehicles-tensorrt/

[5] https://arxiv.org/abs/1510.00149

[6] https://arxiv.org/abs/1802.06367https://ai.intel.com/winograd-2/, Github: https://github.com/xingyul/Sparse-Winograd-CNN

[7] https://arxiv.org/abs/1707.06168,  Github: https://github.com/yihui-he/channel-pruning

[8] https://arxiv.org/abs/1707.06342

[9] https://arxiv.org/abs/1810.11809, Github: https://github.com/Tencent/PocketFlow

[10] https://arxiv.org/abs/1708.06519,  Github: https://github.com/foolwood/pytorch-slimming

[11] https://arxiv.org/abs/1611.06440,  Github: https://github.com/jacobgil/pytorch-pruning

[12] http://xuanyidong.com/publication/ijcai-2018-sfp/

[13] https://arxiv.org/abs/1603.05279,  Github: https://github.com/ayush29feb/Sketch-A-XNORNet

                                                             Github: https://github.com/jiecaoyu/XNOR-Net-PyTorch

[14] https://arxiv.org/abs/1711.11294,  Github: https://github.com/layog/Accurate-Binary-Convolution-Network

[15] https://arxiv.org/abs/1708.08687

[16] https://arxiv.org/abs/1808.00278, Github: https://github.com/liuzechun/Bi-Real-net

[17] https://arxiv.org/abs/1605.04711

[18] https://arxiv.org/abs/1612.01064,  Github: https://github.com/czhu95/ternarynet

[19] http://phwl.org/papers/syq_cvpr18.pdf,  Github: https://github.com/julianfaraone/SYQ

[20] https://arxiv.org/abs/1712.05877

[21] http://on-demand.gputechconf.com/gtc/2017/presentation/s7310-8-bit-inference-with-tensorrt.pdf

[22] https://arxiv.org/abs/1702.03044

[23] https://papers.nips.cc/paper/6390-cnnpack-packing-convolutional-neural-networks-in-the-frequency-domain

[24] https://blog.csdn.net/nature553863/article/details/97631176

[25] https://blog.csdn.net/nature553863/article/details/96857133

[26] https://github.com/NVIDIA/DeepLearningExamples/tree/master/FasterTransformer

[27] https://github.com/onnx/onnx-tensorrt

[28] https://blog.csdn.net/nature553863/article/details/97760040

2018-07-16 14:04:41 jackkang01 阅读数 16996
  • Fast.ai 深度学习实战课程「中文字幕」

    本课程由 Jeremy Howard 教授开设,共8节。目的是让大家在不需要深入研究高水平数学问题的情况下,学习如何建立先进的深度学习模型。 Jeremy Howard 教授结合自己参加 Kaggle 大赛并夺魁的经验认为,传统学院派的教学方式对于大多数学习者来说已经不适用,应该以问题为引导,以实践为驱动,尽快切入到核心理论和核心工具的使用上,掌握深度学习优模型的构建方法。

    17513 人正在学习 去看看 AI100讲师

神经网络有时可以与乐高积木进行比较,在那里你可以构建几乎任何简单到复杂的结构,你的想象力可以帮助你构建。

计算机视觉任务类型

目标识别:物体识别是得到一个原始的图像,任务是给出目标位置和识别物体属于哪个类,另外还有人脸识别,行为识别等

三维重建:摄像机标定,立体匹配

图像描述:根据给定图像,给出描述文字等

深度相机:RGB-D相机,例如手势识别、骨骼跟踪、增强现实等

视觉导航:视觉SLAM,例如ORB-SLAM

图像分割:图像分割是一项复杂的任务,目标是将每个像素映射到它的合法类,例如语义分割、实例分割等

深度学习模型

现在我们已经了解了什么是高级体系结构,并探索了计算机视觉的任务,下面列出最重要的体系结构及其描述:

AlexNet

AlexNet是深度学习的先驱之一——Geoffrey Hinton和他的同事们引入的第一个深层架构。它是一个简单而又强大的网络架构,它为深度学习的突破性研究铺平了道路。下面是作者提出的体系结构的表示。

AlexNet看起来是一个包含卷积层和池化层的简单架构,顶部是全连接层。区分这个模型的是它执行任务的规模和使用GPU进行训练。在20世纪80年代,CPU被用于训练神经网络。而AlexNet仅通过使用GPU提升了10倍的训练速度。

虽然现在有点过时了,但是AlexNet仍然在所有任务上应用深度神经网络的起点,无论是计算机视觉还是语音识别。

Paper     Code

VGG Net

VGG网络是由牛津大学视觉图形组的研究人员引入的(因此有了VGG这个名字)。这个网络的特点是它的金字塔形状,最接近图像的底层是宽的,而最上层是深的。

如图所示,VGG包含随后的卷积层和池化层。池层负责使层更窄。在他们的论文中,他们提出了多种这种类型的网络,随着架构深度的变化。

VGG的优势是:
对于特定任务的基准测试来说,这是一个非常好的体系结构。
此外,VGG的预培训网络在互联网上是免费的,所以它通常用于各种应用程序的开箱即用。

另一方面,它的主要缺点是,如果从头开始训练,训练速度非常慢。即使是在一个像样的GPU上,它也需要一个多星期才能投入使用。

Paper     Code

GoogleNet

GoogleNet(或先启网络)是谷歌研究人员设计的一类架构。谷歌是2014年ImageNet的赢家,在那里它被证明是一个强大的模型。

在这种体系结构中,随着深入(它包含22层,而VGG有19层),研究人员还提出了一种叫做初始模块的新方法。

如上所述,它与我们前面看到的顺序体系结构相比发生了巨大的变化。在单层中,存在多种类型的“特征提取器”。这间接地帮助网络更好地执行任务,因为训练网络本身在解决任务时有很多选择。它既可以选择对输入进行卷积,也可以直接将其池化。

最终的架构包含了这些叠在一起的初始模块的多个。甚至在GoogleNet中,训练也略有不同,因为大多数最顶层都有自己的输出层。这种细微差别有助于模型更快地收敛,因为对于层本身有联合训练和并行训练。

GoogleNet的优点是:
谷歌的火车比VGG快。
一个预先训练好的GoogleNet的大小比VGG要小。VGG模型可以有>500 MB,而GoogleNet只有96 MB

GoogleNet本身并没有直接的缺点,但是它提出了对体系结构的进一步修改,从而使模型执行得更好。其中一个变化被称为Xception网络,在这个变化中,inception模块发散的极限(如上图所示,是GoogleNet中的4)增大了。它现在理论上可以是无限的(因此被称为极端的开端!)

Paper     Code

ResNet

ResNet是真正定义了深度学习体系结构的深度的怪物架构之一。剩余网络(简称ResNet)由多个后续剩余模块组成,这些模块是ResNet体系结构的基本构件。残差模的表示如下

简单地说,一个残馀模块有两个选项,要么它可以对输入执行一组函数,要么它可以跳过这一步。

现在类似于GoogleNet,这些残馀模块相互堆叠,形成一个完整的端到端网络。

ResNet还介绍了一些新技术:
使用标准的SGD而不是花哨的自适应学习技术。这是与一个合理的初始化函数,保持训练完整
对输入进行预处理的更改,其中输入首先被划分为补丁,然后进入网络

ResNet的主要优点是,可以使用数百甚至数千个剩余层来创建网络并进行训练。这与通常的顺序网络稍有不同,在顺序网络中,随着层数的增加,性能升级会减少。

Paper     Code

ResNeXt

ResNeXt据说是目前最先进的对象识别技术。它构建在inception和resnet的概念之上,以实现一个新的和改进的体系结构。下图总结了ResNeXt模块的剩余模块的外观。

Paper     Code

R-CNN

基于区域的CNN架构被认为是应用于目标检测问题的所有深度学习架构中最有影响力的一个。为了解决检测问题,RCNN做的是尝试在图像中出现的所有对象上绘制一个边界框,然后识别图像中的对象。它的工作原理如下:

Faster-RCNN结构

Paper     Code

YOLO

YOLO是目前最先进的实时系统,建立在深度学习的基础上,以解决图像检测问题。如下图所示,首先将图像划分为定义好的边界框,然后并行运行所有这些框的识别算法,以识别它们属于哪个对象类。在识别了这些类之后,它继续聪明地合并这些框,以形成围绕对象的最佳边界框。

所有这些都是平行进行的,所以它可以实时运行;每秒处理多达40幅图像。

尽管与RCNN相比,它的性能有所下降,但它仍然具有实时性的优势,可以在日常问题中使用。下面是YOLO的架构表示

Paper     Code

SqueezeNet

snizenet体系结构是一个更强大的体系结构,在移动平台等低带宽场景中非常有用。这个架构只占用了4.9MB的空间,而《盗梦空间》占用了~100MB的空间!这种剧烈的变化是由一种叫做消防模块的特殊结构引起的。下图是消防模块的表示。

snizenet的最终架构如下:

Paper     Code

SegNet

SegNet是一种用于解决图像分割问题的深度学习架构。它由一系列的处理层(编码器)和相应的一组解码器组成,按像素分类。下面的图片总结了赛格网的工作。

SegNet的一个关键特征是它保留了分割图像中的高频细节,因为编码器网络的合用索引连接到解码器网络的合用索引。简而言之,信息传递是直接的而不是卷积的。SegNet是处理图像分割问题的最佳模型之一

Paper     Code

GAN

GAN是一种完全不同的神经网络体系结构,其中一个神经网络用来生成一个全新的图像,这个新的图像没有出现在训练数据集中,但足够真实地出现在数据集中。例如,下图是对甘斯的分解。在本文中,我已经介绍了GANs是如何工作的。如果你感到好奇,请仔细阅读。

Paper     Code

 

2019-05-27 14:08:31 Tao_758 阅读数 292
  • Fast.ai 深度学习实战课程「中文字幕」

    本课程由 Jeremy Howard 教授开设,共8节。目的是让大家在不需要深入研究高水平数学问题的情况下,学习如何建立先进的深度学习模型。 Jeremy Howard 教授结合自己参加 Kaggle 大赛并夺魁的经验认为,传统学院派的教学方式对于大多数学习者来说已经不适用,应该以问题为引导,以实践为驱动,尽快切入到核心理论和核心工具的使用上,掌握深度学习优模型的构建方法。

    17513 人正在学习 去看看 AI100讲师

前言:从小白入门,通过这次比赛学到很多东西。现在把文档放到这里,希望能够帮助到需要的人。 特别感谢初赛排名第一的YaHei大佬。感谢他开源的代码把我带进了比赛的大门。附上大佬的项目链接:

https://github.com/hey-yahei/ZTE_Challenge2019_MOA

摘要: 本次模型压缩几乎无法重新训练,因此无法采用许多常用的模型压缩算法。针对主办方提供的已经训练完成的模型,主要使用了包括层融合、剪枝、奇异值分解等方法进行压缩。

一、 层融合

​   在神经网络训练的过程中,BN层能够加速网络收敛,并且能够控制过拟合。不过这样也增加了一些运算和参数,因此在推理过程中,可以通过将BN层与卷积层的参数融合的方式,来减少运算,并略微地实现一些模型的压缩。【1】

​   公式:

​   卷积层计算公式:
Y=WX+b Y = W*X + b

​   BN层计算公式:
Xbn=s(Xm)(σ+ϵ)+bbn X_{bn} = \frac{s(X - m)}{\sqrt(\sigma + \epsilon)} + b_{bn}
​   其中:m: 均值, $ \sigma$ : 方差, s: scale, $ b_{bn}$: 偏置, ϵ\epsilon : 滑动系数。

​   融合及将卷积层的输出作为BN层的输入,带入得到

​   融合公式:
Xbn=XsWσ+ϵ+s(bm)σ+ϵ+bbn X_{bn} = X * \frac{sW}{\sqrt{\sigma + \epsilon}} + \frac{s(b - m)}{\sqrt{\sigma + \epsilon}} + b_{bn}
​   得到融合之后的权值:
Wconv=Wsσ+ϵ W&#x27;_{conv} = W\frac{s}{\sqrt{\sigma + \epsilon}}

b_conv=(bconvm)sσ+ϵ+bbn b\_{conv} = (b_{conv} - m)\frac{s}{\sqrt{\sigma + \epsilon}} + b_{bn}

​   层融合对模型压缩的效果并不明显,对比赛所提供模型,层融合之后大小仅下降3KB。对于显存大小及推理时间的提升未做详细的量化分析。

二、 模型剪枝

​   对于一些权重极小的连接,将其去除几乎不会影响模型的准确性,反而在重训练过程中有助于避免过拟合现象的发生。本次针对该模型的剪枝以阈值修剪:去除绝对值低于$ 1*e^{-10}$的连接。关于阈值的设定,刚开始由于没有经验,不敢设很大。后来测试时发现,阈值设为小于1e61*e^{-6}以内剪枝的数量几乎一致。但是当阈值高到1e21*e^{-2}时就会对模型产生毁灭性的影响。本轮剪枝后模型大小下降也并不明显,大约有340KB左右的下降。而且由于在修剪时需要同时对权值和prototxt文件进行修改,未能做到很好地利用代码自动修剪,因此修剪体验一般。

avatar

三、 删除卷积层

   这个想法实在太过于简单粗暴,几乎不可能成为一个通用的压缩方法。幸运的是本次比赛的模型的conv5冗余较大,直接删除后边四层的影响不大,而且赛后其他同学讨论中提到甚至可以直接删除后边五层。必须承认这个方法来自QQ群中一位同学的分享,并非自己发现。我自己在这一部分的工作主要就是修改代码和prototxt文档。这一方式虽然简单粗暴,却十分有效,直接将我从弃赛的边缘拉到了前60名。该方法的主要提升在于对显存占用和推理计算量的降低。对于模型大小的压缩效果并没有很明显,该步使模型大小减少了大约8.4MB。

四、 奇异值分解

​   奇异值分解(Singular Value Decomposition, SVD)是本次比赛所使用的最主要的压缩手段,效果也是最明显的。

avatar

avatar

​   由于全连接层占据了模型中最大一部分的参数,对全连接层作奇异值分解可以得到极大的压缩收益。因此本次将SVD作为了模型压缩的重点。有几天的工作都花在了测试不同的r值对模型准确率的影响上。并且希望能够找到合适的r使得z恰好处于临界点(0.950或0.900)。最终,本次最好成绩对应的r值为136, 对应的z值为0.958。也许是由于服务器波动等因素,在r=130时,z取值为0.951,却并未得到更加理想的成绩。而使z接近0.9的r值为108,此时z值为0.901,但权值的下降并没能换来足够的显存使用及计算量的改善。这一部分对于运算速度和显存占用有着显著的优化,同时对模型的大小有着更为显著的压缩。在r=130时,模型大小下降了大约190MB, 比原来压缩了大约63%。

五、 其他未成功应用方法

(1)无需数据的卷积网络自动加速

​   无需数据的卷积网络数据加速(Data-free Automatic Acceleration of Convolutional Networks, DAC)是由Xin Li 等人与2018年提出的一种无需重新训练模型的压缩方式【2】。将卷积核分解为Depthwise 及 Pointwise两种,分解运算的核心其实还是奇异值分解。最终可以实现对已训练完成的模型的卷积核分解与替换,以及权值的迁移,而无需重新训练。原文作者在CIFAR-VGG模型上测试,发现替换靠后的卷积层可以在减少较多参数的同时只造成很小的精度损失,而处理较为靠前的卷积层则代价较大。
附上自己实现DAC的代码

https://github.com/baizhenmao95/2019-ZTE-Algorithm-Competition/blob/master/DAC_AGAIN.py

avatar

​   由于论文中给出了该算法的详细步骤,因此我尝试用代码复现了该算法,并对卷积层conv4_5_2进行了替换。虽然最终确实可以得到压缩后的模型,将r取为5时大约能够减少该层一半的参数。但是也许是我的程序实现有误,也许是该算法并不适用于该类模型的压缩,甚至也许是所选的用于替换的卷积层并不合适,总之最终得到的模型与原模型相比,所提取的特征图的余弦距离出现了负数。最后一天我压宝压在了这一算法上,却最终没能实现突破,也是一大遗憾。

(2) Octave Conv

​   OctaveConv是前几天刚出现的一个新的方法。一出现就得到了许多深度学习相关的学者和媒体的大力推荐。而其简单有效的思想也让我印象深刻。因此十分希望能够复现其中的结果,并在此次比赛中为我所用。作为一个新的方法,使用它的优势在于我可能会是比赛中为数不多的使用者,也就有可能得到几乎独一无二的改善。但是劣势在于,过于新鲜的方法意味着对其的解读与代码的实现方面可能很有限。因此在将近一周的时间内我只能对照着论文原文【3】和某个MXnet版本的第三方复现代码【4】学习。它即插即用、无需更改网络结构的特性非常吸引人,而其通俗易懂的比喻也降低了对算法的原理及其效果的理解难度。可惜最终我还是意识到它似乎是一个需要重新训练的算法,最终只能遗憾放弃。但是在之后的科研工作中也许能够真正地用到。因此也算是一项不错的收获。

avatar

(3)DEEP COMPRESSION

​   这一压缩操作来自于一篇很经典的模型压缩论文【5】以及一个caffe版本的第三方复现代码。主要做了基于Kmeans聚类的量化来压缩卷积和全连接层的权重。经过压缩后得到了一个大约只有8MB的numpy模型文件。这对于嵌入式设备的使用非常友好。但是也许由于参数选取不合适等原因造成了z值的大幅下降,最终只能弃用。但该算法的实用意义也许要大于比赛意义。

附参考资料:
【1】 https://blog.csdn.net/u013597931/article/details/85697008
【2】https://arxiv.org/pdf/1812.08374.pdf
【3】https://export.arxiv.org/pdf/1904.05049
【4】https://github.com/terrychenism/OctaveConv
【5】https://arxiv.org/pdf/1510.00149v5.pdf

没有更多推荐了,返回首页