欢迎光临
我们一直在努力

CentOS安装TensorRT指南

andy阅读(1604)

首先介绍下tensorRT,tensorRT类似于tensorflow serving,都是一种用于将训练好的深度学习模型用于实时inference的工具,区别在于tensorflow serving是以一种server的方式提供出来的也就是grpc服务,而tensorRT目前是以一种library的方式提供的,当然我们可以自行包装成一个server,其实NVIDIA官方也已经有基于tensorRT的Inference Server了这个是后话。

相比于tensorflow serving,tensorRT对gpu的支持更加的好,inference更加快,毕竟是NVIDIA自家的;并且tensorRT支持多种深度学习框架,比如tensorflow、caffe、paddle paddle,pytorch等,tensorflow serving的话虽说也可以通过扩展的方式来支持,但是比较麻烦而且非官方。

caffe模型的话可以直接导入,其他深度学习框架的模型需要通过tensorRT的parse工具转换成UFF格式,或者是ONNX标准。tensorRT甚至支持以编程的方式直接添加layer,并设置参数。

好了上面是简单介绍下tensorRT,下面讲下如何在centos上安装。tensorRT的官方是比较支持Ubuntu的,提供的文档也基本基于Ubuntu。本文是基于Centos7.5, Tesla M40的。

1.首先你需要安装好NVIDIA驱动、cuda、cudnn,我的机器已经安装了 不多说,网上的教程也多的是。 这里要注意NVIDIA的driver要375以上版本的,cuda我这里用的是9.0,cudnn我用的是7.1。

2.安装好上面步骤之后,到这里https://developer.nvidia.com/nvidia-tensorrt-download 下载tensorRT 4.0的安装包,注意要选对符合你cuda和cudnn的对应版本的,另外这里列出的都是Ubuntu的,没关系,我们不选tar file installed packages。

3.下载完后,解压,接着 vi ~/.bashrc,添加如下内容


1
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/andy/TensorRT/lib:/usr/local/cuda-9.0/lib64

其中/home/andy/TensorRT替换成你自己实际的目录,cuda-9.0也是。


1
source ~/.bashrc

使之生效。

4.然后就是安装对应的python库,包括tensorRT,uff和graphsurgeon。
方法是直接用pip install对应的whl包,几个包分别在tensorRT目录下的python、uff、graphsurgeon目录下,进到这三个目录下,执行 pip install xxx.whl即可。

搞定后,进到python环境下,执行下import tensorrt,正常的话可以成功导入。

5.最后可以编译一下tensorRT提供的一些sample。进到tensorRT的sample目录下,执行make CUDA_INSTALL_DIR=/usr/local/cuda,完成后到tensorRT的bin目录下,可以看到已经生成了可执行的sample,执行./sample_mnist 就可以输出一副字符组成的数字图片,下面跟着mnist的预测结果。 ok整个安装搞定了。

过程中可能会遇到的错误
1.报错


1
libnvparsers.so: undefined reference to `std::invalid_argument,undefined reference to `std::__throw_out_of_range_fmt(char const*, ...)

解决方法:gcc的版本问题,可以升级到gcc5.3,然后在环境变量中替换老的gcc,并且把新的gcc的glibc替换原有的旧的

关于SBT你需要知道的那些事

andy阅读(2161)

关于SBT你需要知道的那些事

之前在做一个有关spark的项目的时候,需要使用sbt构建scala代码,以前主要用maven,gradle也用一点,但是sbt实在陌生,摸索了一阵,把自己在使用sbt中最需要了解的东西记下来,以备同样不熟悉的同学做个参考。

SBT常识

sbt是个类比于maven、gradle的构建工具,主要用于scala项目 当然也可以用于别的。一个标准的sbt项目具有如下结构


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
build.sbt                   <- sbt构建定义文件,后缀名必须是.sbt,前边可以是任意名字,不要求必须是build
project/                    <- project目录下的所有.scala与.sbt文件都会被自动载入
  build.properties          <- 指定sbt的版本,如sbt.version=1.0.0,sbt启动器会自动安装本地没有的版本
  Dependencies.scala        <- 依赖配置,如果依赖较简单,可以省略该文件,直接写在build.sbt中
  plugins.sbt               <- 插件定义
src/
  main/
    resources/
    scala/                  <- scala源文件
    java/
  test/
    resources/
    scala/                  <- scala测试源文件
    java/
target/
bin/

最核心的当然是build.sbt这个文件,类比于maven中pom.xml 这个文件可以用scala语言编写,也可以包含一些特定的sbt的语法的东西,所以有时候看上去比较奇怪。
总结一下最基本的配置方式是key := value的方式

如何解决SBT在国内太慢的问题

我使用sbt的第一个问题就是太慢了,sbt里虽然可以使用maven的仓库 但是好像并没有继承maven的settings.xml配置的mirror,所以这里我们要对sbt做一下镜像的配置,比较合适的一个可以是这样


1
2
3
4
5
6
7
[repositories]
local
aliyun-nexus: http://maven.aliyun.com/nexus/content/groups/public/
typesafe: http://repo.typesafe.com/typesafe/ivy-releases/, [organization]/[module]/(scala_[scalaVersion]/)(sbt_[sbtVersion]/)[revision]/[type]s/[artifact](-[classifier]).[ext], bootOnly
sonatype-oss-releases
maven-central
sonatype-oss-snapshots

SBT如何添加依赖

一个最基本的build.sbt文件


1
2
3
4
name := "sss1"
version := "0.1"
scalaVersion := "2.11"
libraryDependencies += "org.apache.spark" %% "spark-core" % "2.1.1"

就像前面说的,最基本的就是key := value
然后添加依赖就是libraryDependencies += “groupid” % “artifactId” % “version”
其中第一个百分号可以换成双百分号”%%”,表示在artifactId上补上当前的scala版本,比如上面的那个最终的依赖坐标就是 groupId:org.apache.spark, artifactId:spark-core_2.11, version:2.1.1

SBT如何添加本地依赖

这个很方便,SBT默认会把项目根目录下的lib目录作为“非托管依赖”,所以只要将你的jar包放到这个目录就可以了,当然如果的jar不想放在这个目录(我也不知道为什么,老子就是不想放在这个目录)这种情况你可以在build.sbt中配置


1
unmanagedBase := baseDirectory.value / "custom_lib"

SBT如何打印依赖树

方法可能很多,但是最简单,效果最好的方法就是利用一个插件
编辑 ~/.sbt/0.13/plugins/plugins.sbt 加上一行


1
addSbtPlugin("net.virtual-void" % "sbt-dependency-graph" % "0.8.2")

然后在项目根目录进入 sbt console
然后执行命令

1
tasks -V

会列出当前项目可用的sbt命令,你会发现多了一些dependency开头的,就是插件提供给我们的,我比较喜欢的一个命令是

1
dependencyBrowseGraphHtml

可以生成一个依赖树的HTML页面 比较直观。如下图
sbt查看html依赖树

由于本人也是刚开始使用sbt 遇到的问题还比较少 所以此文会继续保持更新

java通过gRPC整合tensorflow serving——gRPC java入门例子

andy阅读(2202)

java通过gRPC整合tensorflow serving——gRPC java入门例子

项目中以前需要把算法同事们train好的tensorflow model包装成服务提供给其他部门应用,一开始我们使用python直接调用tensorflow,然后java和python之间的交互 通过jni或者rabbitmq的方式,这种方式的问题就是调用tensorflow的效率较低,不得不频繁的load model的checkpoint文件,推断执行慢,后来随着tensorflow官方推出tensorflow serving,我们也尝试了这种方式,发现确实可以很大程度上提升推断的性能,从一开始调用tensorflow每一次推断差不多要几秒钟(导致我们的服务一开始基本都是只能提供异步批量处理的方式),后来的tfserving的方式 耗时降到了百毫秒的级别,使得同步的调用成为现实。

这几篇文章就简单讲一下在实践中,我们是如何通过gRPC整合tensorflow serving调用深度学习模型的。

打算分为以下几个部分

  1. 首先必须要知道一些gRPC的基本知识,能用java实现一个客户端和服务器端的小demo 就是本篇gRPC java入门例子
  2. 然后是 tensorflow model导出到tensorflow serving的要点讲解
  3. 接着是一个完整的java通过gRPC调用tensorflow serving的例子。

下面开始本篇,首先关于gRPC的介绍就不多说了,网上随便一搜都是,什么高性能,以支持移动和HTTP2.0为主的开源RPC协议什么的。。。

我们直接开始java的小demo,我基于Intellij的iDE讲解,eclipse大体也差不多。

1. 首先第一步,新建一个基于gradle构建的java项目,如图
java整合tensorflow serving

java整合tensorflow serving

然后点下一步,填写maven坐标什么的,按照自己实际情况填写就好了,最后点finish,一个gradle项目就建好了。

2.接着加入相关的依赖和插件

因为我们需要gRPC的支持所以需要加入grpc几个相关的依赖,还有一个protobuf的gradle插件,用于将proto的协议文件生成java源码。

编辑build.gradle 如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
group 'com.xyz'
version '1.0-SNAPSHOT'

repositories {
mavenCentral()
}

buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.3'
}
}

apply plugin: 'java'

apply plugin: 'com.google.protobuf'

sourceCompatibility = 1.8

protobuf {
generatedFilesBaseDir = "$projectDir/src/"
sourceSets {
main {
proto {
// 除了默认的'src/main/proto'目录新增proto文件的方法
srcDir 'src/main/protobuf'
include '**/*.protodevel'
}
}
}
protoc {
// The artifact spec for the Protobuf Compiler
artifact = 'com.google.protobuf:protoc:3.0.0'
}
plugins {
grpc {
artifact = 'io.grpc:protoc-gen-grpc-java:1.0.0-pre2'
}
}
generateProtoTasks {
all()*.plugins {
grpc {}
}
}
}

dependencies {
compile 'com.google.protobuf:protobuf-java:3.0.0'
compile 'io.grpc:grpc-stub:1.0.0-pre2'
compile 'io.grpc:grpc-protobuf:1.0.0-pre2'
compile "io.grpc:grpc-netty:1.0.0-pre2"
if (JavaVersion.current().isJava9Compatible()) {
compile 'javax.annotation:javax.annotation-api:1.3.1'
}
testCompile 'junit:junit:4.12'
}
3.接着 就是编写我们的服务协议定义的proto文件

在src/main/目录下新建一个proto目录,默认gradle-protobuf插件会自动处理这个目录下的proto文件,如果你想自己定义其他目录,就要像上面那个配置文件中那样,添加proto–srcDir的配置单元了,这里我起一个名字叫test_grpc.proto 内容如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
// Copyright 2015, gRPC Authors
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
syntax = "proto3";

option java_multiple_files = true;
option java_package = "io.grpc.examples";
option java_outer_classname = "TestGRPCProto";

package examples;

service TestService {
rpc ListPeople (Query) returns (People) {//无办法不传参数 只能定义一个空消息 传进去 ,我想这可能是也是一种防御性编程吧 毕竟后面可能会用到参数

}

}

message Query {

}

message People {
string name = 1;
int32 age = 2;
}

就是简单的定义了一个叫TestService的服务,然后只有一个方法叫ListPeople,方法接收一个空的参数,但是gRPC不允许这种完全空的,只能通过自己定义个空消息实现,ListPeople返回一个People的对象,都是写死的,做个演示。

保存后,执行gradle build,或者其他触发编译的命令,protoc就会将刚才的proto文件生成对应的java代码,拷贝这些代码到我们的src/main/java目录,下面就可以开始编写服务代码了。

4.然后我们编写服务端

新建一个叫TestServer.java的源文件,主要的步骤就是首先写一个服务类继承刚才gRPC自动生成的那堆代码中的服务stub类,就是XXXImplBase类,其中的XXX就是你proto中定义的服务名,覆写里面的服务方法后,然后再写一个启动server的代码就ok了,具体如下图,作为demo可以直接拷贝

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
package io.grpc.examples;

import io.grpc.Server;
import io.grpc.ServerBuilder;
import io.grpc.stub.StreamObserver;

import java.io.IOException;

public class TestServer {

private Server server;

private void start() throws IOException {
/* The port on which the server should run */
int port = 50051;
server = ServerBuilder.forPort(port)
.addService(new TestServiceImpl())
.build()
.start();
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public void run() {
System.err.println("*** shutting down gRPC server since JVM is shutting down");
TestServer.this.stop();
System.err.println("*** server shut down");
}
});
}

private void stop() {
if (server != null) {
server.shutdown();
}
}

/**
* Await termination on the main thread since the grpc library uses daemon threads.
*/

private void blockUntilShutdown() throws InterruptedException {
if (server != null) {
server.awaitTermination();
}
}

/**
* Main launches the server from the command line.
*/

public static void main(String[] args) throws IOException, InterruptedException {
final TestServer server = new TestServer();
server.start();
server.blockUntilShutdown();
}

static class TestServiceImpl extends TestServiceGrpc.TestServiceImplBase {
@Override
public void listPeople(Query request, StreamObserver responseObserver) {
People people = People.newBuilder().setAge(11).setName("xiaozhang").build();
responseObserver.onNext(people);
responseObserver.onCompleted();
}
}
}
5.最后就是client端的调用代码了

新建一个类TestClient.java 拷贝以下代码, 其中调用gRPC的服务client分为两种,一种是blocking的同步调用,一种是non-blocking的异步调用,代码的注释中有这块,可以参考。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
package io.grpc.examples;

import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
import io.grpc.stub.ServerCallStreamObserver;
import io.grpc.stub.StreamObserver;

public class TestClient {
public static void main(String[] args) throws InterruptedException {
ManagedChannel channel = ManagedChannelBuilder.forAddress("127.0.0.1",50051).usePlaintext(true).build();
TestServiceGrpc.TestServiceBlockingStub blockingStub = TestServiceGrpc.newBlockingStub(channel);
TestServiceGrpc.TestServiceStub ayncStub = TestServiceGrpc.newStub(channel);

//同步调用
System.out.println(blockingStub.listPeople(Query.newBuilder().build()));
//异步调用
ayncStub.listPeople(Query.newBuilder().build(), new StreamObserver(){
@Override
public void onNext(People value) {
System.out.println(value);
}

@Override
public void onError(Throwable t) {

}

@Override
public void onCompleted() {
System.out.println("finished");
}
});
System.out.println("异步调用不阻塞,所以这句先打印");
Thread.sleep(10);
}
}

最后启动server,再启动服务端就可以看到简单的效果了,时间仓促,有问题敬请留言。有了对java使用grpc的简单印象后,后面我们继续探讨整合tensorflow serving的方式。

深度学习资源整理,不断更新中

andy阅读(1333)

深度学习资源整理,不断更新中

基础知识:
线性代数
  1. 麻省理工公开课线性代数,  网易版http://open.163.com/special/opencourse/daishu.html
  2. 线性代数应用课程:Coding the Matrix: Linear Algebra through Computer Science Applications

    链接: https://pan.baidu.com/s/1o7AXQrC 密码: 84yi

  3. B站搬运工 线性代数的本质-合集  内容:01 – 向量究竟是什么  02 – 线性组合、张成的空间与基  03 – 矩阵与线性变换、04 – 矩阵乘法与线性变换复合、附注1 – 三维空间中的线性变换、05 – 行列式、06 – 逆矩阵、列空间与零空间、附注2 – 非方阵、07 – 点积与对偶性、08第一部分 – 叉积的标准介绍、08第二部分 – 以线性变换的眼光看叉积、09 – 基变换、10 – 特征向量与特征值、11 – 抽象向量空间   地址https://www.bilibili.com/video/av6731067/
微积分
  1. 俄亥俄州立大学微积分基础 coursera https://www.coursera.org/learn/calculus1
  2. 数列与级数  讲课老师说话非常有意思  确切的说表情非常用力  https://www.bilibili.com/video/av1354315
概率论

台大概率课程 链接: http://pan.baidu.com/s/1mis8w8C 密码: gqun

 

python编程基础
  1. Learn to Program: The Fundamentals

    链接: http://pan.baidu.com/s/1eSlZbR8 密码: fwr6

神经网络
  1. Andrew Ng (吴恩达)深度学习专项课程 coursera链接 网易云课堂字幕版链接
  2. 深度学习三巨头之一Geoffrey Hinton 大神的 面向机器学习的神经网络(Neural Networks for Machine Learning)
    https://www.coursera.org/learn/neural-networks?siteID=PYQagbz7Hd0-MeOm9SQ6gC2NixSjmgOkBw&utm_content=2&utm_medium=partners&utm_source=linkshare&utm_campaign=PYQagbz7Hd0
    这门比吴恩达的要难一些 但是没有作业 只有小测
  3. Udacity优达学城的深度学习免费课程 来自google 主要基于tensorflow的应用 https://cn.udacity.com/course/deep-learning–ud730

中文的

  1. 台大李宏毅老师深度学习课程
    课程主页:http://speech.ee.ntu.edu.tw/~tlkagk/courses_MLDS17.html
    课程视频Playlist: https://www.youtube.com/playlist?list=PLJV_el3uVTsPMxPbjeX7PicgWbY7F8wW9
    B站搬运深度学习课程视频: https://www.bilibili.com/video/av9770302/
  2. 台大美女老师陈缊侬老师深度学习应用课程:Applied Deep Learning / Machine Learning and Having It Deep and Structured

16年课程主页,有Slides等相关资料:https://www.csie.ntu.edu.tw/~yvchen/f105-adl/index.html
17年课程主页,资料正在陆续放出:https://www.csie.ntu.edu.tw/~yvchen/f106-adl/
Youtube视频,目前没有playlist,可以关注其官方号放出的视频:https://www.youtube.com/channel/UCyB2RBqKbxDPGCs1PokeUiA/videos

特别推荐

莫烦Python及机器学习教程  这个特别适合入门,内容深度虽然很浅,但是比较通俗易懂,也算包罗万象,而且小哥哥的声音非常甜美哈哈  传送门http://morvanzhou.github.io/