老板想让我快速上线模型,但我连Linux还不会用(上)


点击上方 AI派 ”, 选择“ 设为星标 最新分享,第一时间送达! 640?wx_fmt=gif
作者:Leon Wang, 现为中科院特别研究助理 (博士后),在 AI、数据科学和科学计算等方面相关的工程实践上积累了丰富的经验。 编辑:王老湿

大家好,这是《AI炼丹炉工程实践指南》专栏的第二篇,在上一篇给大家介绍了什么是AI项目的工程素养,我们这个专栏的目的是为了帮大家解决落地AI项目中遇到的各种坑或者学习一些AI工程必备的能力,比如在工作中会遇到这样的问题:我们的模型离线训练成功后,老板想让你快速将这个模型上线(部署到生产环境的Linux服务器)来解决一些业务问题,这时候(平时Windows操作系统用的贼溜的)你傻眼了,我这Linux系统都还不使用,让我怎么去部署模型。


遇到上面的问题别担心,今天我就向大家来介绍Linux命令方面的一些知识,并从数据科学或者AI角度重点介绍一些常用的命令。因为这块内容比较多,因此Linux命令基础分为上下两篇进行介绍,本文是其中的上篇,并且会在文章末尾给大家放一个炫酷的Linux操作系统演示视频。

Linux命令行

Linux命令行长什么样

考虑到大部分朋友平时还是用Windows比较多,所以第一部分还是先对Linux命令行做个基本介绍。

我们先来看Linux命令行长什么样子。在下面的截图中,我们可以看见的黑色窗口是命令行的终端(Terminal),闪动的光标前面是起始符,表示当前的命令行环境。

640?wx_fmt=png

我这里使用的命令行环境是Oh-My-Zsh,并且通过一系列配置,显示了当前活动网络的IP地址,当前目录,操作系统,甚至当前时间和磁盘剩余空间,以及上一条命令的执行时间,省了我很多敲命令查看的时间。这里没有用比较常见的bash那种枯燥的$举例,也是想告诉大家,每个人的Linux可以是完全不同的样子,也希望通过后续的介绍,大家都可以根据自己需求配置出最有效率的Linux环境。

在这个终端窗口中,我们可以进行下面两种操作方式:

  • 敲入单个命令,与终端进行交互式对话。

  • 执行一个脚本批量执行一系列命令。

终端是负责用户与Linux命令行程序交互的界面。而Linux命令行实际的程序就是shell程序。我们能接触到的最常见的shell程序就是bash

Linux下的命令有几个小技巧值的掌握:

  • 通过上下箭头,可以重复历史命令

  • 打出前几个字母后,再按TAB键可以快速补全命令

Linux下的脚本集成

大部分用过Python或Matlab的朋友可以发现,Linux终端窗口的这种使用方式与我们常用的这些软件非常类似。那为什么有了Python等软件,我们还需要多掌握一个Linux命令行?我暂时能想到的部分原因有:

  • 命令行有许多功能是开箱即用,不需要我们额外开发

  • 命令行可配置,可扩展。自己配置熟练后,使用起来高效便捷

  • 命令行下的shell命令或shell编程也可视作一种胶水语言,我们可以通过Linux命令行环境无缝集成Python、R甚至Octave等脚本程序。

Octave可能是Matlab开源替代中最好的方案。吴恩达在机器学习课程中,就推荐过开源免费的Octave

我专门说下最后一个方面——脚本的集成。在安装好Python、R等计算环境后,我们就可以在Linux命令行环境使用这些pythonRscript新命令来执行Python或R脚本,我们可以在一个跑模型的脚本里,分别调用不同语言实现的逻辑,例如下面一个脚本示例:

#!/bin/bash
#  raw data downloading
wget http://xxxxurl.tar.gz
# data processing
python data.py
# model training
Rscript model.R
……

在上面的例子中,我们通过一个简单的脚本就分别调用了Linux的命令、Python和R下面的功能,分别实现一个非常雏形的模型pipeline。

`shebang`符号

可能部分朋友对上述第一行的#!/bin/bash不熟悉,#是Linux命令行中的注释,指明其后的本行内容不执行。注释后面又跟了特殊的感叹号,表示后面不是一般的注释信息,而是类似脚本文件头的特殊信息。更详细的说,#!叫做shebang符号,为shell环境指明当前脚本要执行的默认解释器,如果外部显示指明解释器,则该行不起作用。例如这里的/bin/bash,就是最常见的shell环境bash的解释命令。

Linux 中国翻译组为#!取了中文名叫释伴,意为解释伴随行,又为shebang的音译,非常巧妙

特别注意在Linux下,Python、R或Octave等脚本都可以使用shebang和增加执行权限的操作,变成可以在Linux下直接运行的脚本。例如,我们可以在每个py文件前,加入#!/usr/bin/env python3。这时,shebang为shell环境提供隐式的python解释器。

这里的#!/usr/bin/env python3表示通过环境变量$PATH去寻找python3,比直接写的#!/usr/bin/python3灵活。因为Python的版本很多,Python2和Python3还存在不兼容问题,我们经常需要通过切换环境变量,或者直接切换虚拟环境更改Python解释器去执行不同的代码。上面的写法可以自动通过环境变量找到所需要的实际Python位置,简单来说就和自己敲python执行的是同一个Python解释器;而如果写成#!/usr/bin/python3,则会直接去执行该路径的解释器命令,即使我们可以手动就改成每个实际需要的路径,也很麻烦,而且很容易出错。

此时,前面的脚本示例可以改成下面的形式:

#!/bin/bash
#  raw data downloading
wget http://xxxxurl.tar.gz
# data processing
./data.py
# model training
./model.R
……

通过上面的一个小改动,所有外部程序写的脚本都能以一种更加无缝的方式集成到统一的pipeline中。这也解释了前面一期说的,为什么Octave要把Maltlab的注释专门改为#

Linux命令基本使用方法

Linux命令的基本使用方法是命令 [参数1 [参数2 ……]],这里的命令就是表示具体要执行的命令名字(例如lswhoami等),[参数1]表示后面可能出现的参数,具体的参数个数要看命令的功能。命令可以不需要参数,也可能需要一个或多个参数,具体可以利用man 命令命令 --help(部分命令的帮助需要执行命令 -h)查看。由于篇幅限制,专栏不会列出每个命令的每种用法,主要从数据科学或AI从业人员看待常用命令和用法的角度来介绍这些命令,大家在今后的学习中可以自己去查阅其他的用法,也可以在交流群里随时交流。

很多新出现的Linux命令,其实都是开源作者用Python等语言实现的小程序。我们在了解Linux命令常见的形式后,可以借助Python中的argparse等类似功能去开发自己的命令。

Linux的几个知识点

从Windows切换到Linux,最容易有所不适的两个方面就是权限和编码。Linux中有着完善清晰的权限体系,比如我们想要直接执行脚本,就需要增加脚本文件的执行权限。同时,不同用户对不同文件的读写权限是分开管理,而Linux下的一切皆文件,所以我们几乎可以用命令控制和改变Linux 的所有。

权限与用户

Linux的文件权限类型包括读、写和执行,分别对应r、w和x。这些权限基于用户组分别设置,每个文件需要明确,文件所有者,用户群组和其他组三类用户的各自权限

更改文件权限
  • 更改文件权限的命令是chmod,一般常用场景是,写完一个脚本的文本文件doit.sh ,默认是权限位是-rw-r--r--,其中第一位为d时表示目录,否则为文件。其余分别表示文件所有人(创建文件的用户)可读写,不可执行;用户所在群组的其他用户和其他用户群组只能读。为能直接运行脚本,需要执行chmod +x doit.sh,则文件的权限位变成-rwxr-xr-x, 说明chmod为这三个权限位全部加上了可执行权限。

我们可以用一种可能更常见的权限数字写法,例如chmod 755 doit.sh,会得到同样效果。这种写法的数字 4 、2 和 1 表示读、写、执行权限,两种以上权限可以通过加法组合表示,即 rwx = 4 + 2 + 1 = 7 ;rx = 4 +1 = 5 。如果我们知道16进制就很容易理解。

还有一种情况,我们还需要更改文件所有者才能进行操作,命令是chown 用户名:用户组 路径, 一般假设当前用户是user1,默认用户组也是user1,就可以用chown user1:user1 -R path

root权限

经常玩手机的朋友会知道手机有root权限的说法。安卓系统源于Linux,自然Linux里就有一样的root权限的设定。比如我们在使用一些命令时,系统经常不允许当前用户来更改,我们需要用root权限来强行完成这个目的,做法有以下两种:

  • 使用sudo su, 然后输入当前用户密码切换到root中,你就可以不受约束,做任何事情;执行完操作后,exit退出root账户

  • 使用sudo 执行命令,临时提权为root权限。比如更改一些文件所有者时,往往需要sudo chown ….,这时也会提示输入当前密码继续执行。

?‍♂️这里可以留一个问题,你认为上述两种的方式中,那一种更好呢?理由是什么?

对了,差点忘记要特别提示一点切换到root后做一切改动请三思而后行请三思而后行请三思而后行!重要的事情说三遍!!!

编码与换行

从Windows切入Linux后,很容易踩的另外一个坑就是文件编码。其实这完全不能怨Linux,因为问题都出自Windows那坑爹的设定。在Windows下,所有文件编码默认都和当前操作系统语言强关联,比如我们简体就是gb2312gbk,繁体是Big5之类的。而Linux下为了统一不同语言,避免造成转换的麻烦,和mac等很多其他系统一样,默认都是utf-8编码。

UTF-8 编码俗称万国码,是统一不同语言编码方式的一种多字节编码。UTF-8对英文使用单字节(8 位),中文使用三个字节(24 位)编码。UTF-8编码优势主要体现在,欧美国家用户浏览中文网页时,若是UTF-8编码则可以直接浏览。若是gbk网页,则需要用户下载中文语言包才能显示。这也是为什么网页上也都采用UTF-8编码的原因。

我们如果直接打开从Windows传到Linux的文件,系统就会默认用utf-8解码的方式去解释gb2312,就得到的错误的乱码。假如我们不方便回Windows重新导出utf-8的文件,我们可以用下面命令:

iconv -f gbk -t utf-8 -c text.txt -o text.out

这条命令可以将从gbk编码转换的text.txtutf-8编码的text.out。当然我们还可以直接用支持gbk的编辑器打开。

简体中文系统下,Windows记事本里的ANSI编码代表GB2312

另外,Windows下的换行符与Linux不同。最常见的表现就是,我们在Linux中生成的文本数据,用Windows记事本打开会发生错行。这是因为Windows的文件换行符是[CR][LR],但Linux或Unix,安卓等为[LF]。在实际研发和生产环境中,特别容易出现的一个大坑是,脚本命令经过Windows系统读写后,换行符发生变化导致脚本在Linux中执行出错。这时候我们需要借助一个有用的小命令dos2unix,将这些有问题的脚本转换回Unix换行符。

可能有些不了解Linux历史的朋友会觉得奇怪,为什么Linux很多都和Unix很相似。Linux实际是Unix的开源替代,因此大量设定都遵循历史悠久的Unix形成的规则。而Windows上的很多习惯规定都很独立特行,不兼容Linux和Unix等系统的统一风格,所以很多锅实际都不能由Linux来背。

包管理器命令

Linux下有着Windows完全不能比的完整开发工具链和包管理器,绝大部分软件和程序的系统依赖包都可以直接用apt进行安装。

这里直接以数据科学和AI最常用的Ubuntu进行举例,若Centos系统则可以用yum等命令完成类似操作,请读者自行查阅学习或在交流群进行讨论。

  • 更新与升级

这里需要先说明,Linux通过软件源中的软件列表指明各个包的元信息,通常我们在安装一个软件包之前,最好先进行软件源列表的更新,命令如下:

sudo apt update 

执行完update命令,有时会提醒有软件版本可以更新,我们可以使用upgrade命令进行升级:

sudo apt upgrade 
  • 安装,卸载和清除

进行了必要的软件源更新后,我们可以直接用apt进行相应包的管理操作:

sudo apt install xxx   # 安装xxx
sudo apt remove yyy # 卸载yyy
sudo apt purge zzz # 卸载并清除yyy的信息
  • PPA操作

Ubuntu中的软件源默认只有非常稳定,且版本很旧的软件包。但很多与数据科学相关的软件包,采用了比较新的依赖开发而成,一般我们很难有机会直接在默认软件源中找到。Ubuntu提供了一种PPA的方式,可以通过这种方式,添加第三方最新的软件信息到软件源列表。

Ubuntu添加PPA 的方法有很多,大部分教程说的是直接编辑系统的sources.list文件。这里为大家推荐以下命令:

sudo add-apt-repository ppa:user/ppa-name

其中,ppa:user/ppa-name是常见的PPA形式。比如,以前我们可以在Ubuntu中安装Java的PPA:

sudo apt-add-repository ppa:webupd8team/java

目前,由于众所周知的原因,上面的PPA已经作废了。同时,奉劝各位公司里还用着MySQL的工程师或CTO,趁早构思下以后的数据库替代方案,不要临时抱佛脚。

通过添加PPA到软件源的方式,以后的软件安装就可以直接用apt搞定,而不必自己去找安装包。这条命令可能在有的机器上会报错,这时候我们只需要执行以下命令,安装命令需要的软件包即可:

sudo apt-get install software-properties-common
本地软件包操作
  • 安装本地软件包

    apt命令是Ubuntu中在线安装软件包的命令。如果我们下载好xxx.deb文件,此时需要用下面命令:

 sudo dpkg -i xxx.deb

或者是

 sudo gdebi xxx.deb

命令去安装。

这里注意,deb代表的是Debian的软件包格式,Ubuntu继承自Debian发行版,所以沿用这一格式。

  • 搜索已安装软件包

平时在使用中,我们经常需要查看已经安装的软件信息。比如,我们想查看本地已经安装的含有python关键词的软件包信息:

dpkg -l |grep -i python

其中,dpkg -l是列出所有本地软件包信息,grep -i python是在文本中搜索关键词,但忽略大小写。如果不加-i参数,默认对大小写敏感。

  • 删除软件包

我们在前面可以通过apt removeapt purge删除或清除掉软件包。但如果软件包是从本地用deb文件安装,这是需要用以下命令进行删除:

sudo dpkg -r xxx  # 删除 xxx
sudo dpkg -P xxx  #删除并清除xxx软件包和信息

通常,我们需要清除的软件,存在多个软件包,如果我们分别一个个去删除,效率会很低。假设我们想删除掉所有python相关的软件包,可以用以下的命令:

dpkg -l |grep -i python |awk '{print $2}'| xargs  dpkg -r

其中,awk '{print $2}'表示在前一个管道输出的内容的中,提取出第二列,通过观察我们可以发现正好是软件包的名字。然后通过xargs命令,将前面批量输出的软件包作为dpkg -r的参数,批量去执行。

特别注意,不要随便删除Linux系统上安装的python。因为Linux系统里,有很多系统软件依赖python。如果我们非要通过命令卸载python,会使得很多系统功能出问题!

另外,awk是Linux命令中及其强大的一个文本处理命令,我们可以先记住awk '{print $n}'这条命令,在管道符组合Linux命令时,这条命令非常有用。

  • 本地包文件查询

我们经常需要查询本地安装的软件中的文件路径。比如,我们想知道系统已经安装的python的位置,这时候可以用命令:

dpkg -l python3.6

命令连接

Linux的命令可以通过不同的组合方式完成一个复杂的数据科学处理任务。

  • 逻辑和运算符

这种场景一般最常见是有逻辑的批量执行多条命令,比如前面提到的软件源更新和软件安装两条命令就可以一次执行,不需要等待一条命令结束再执行下一条命令。

sudo apt update && sudo apt install xxx

其中,&&表示的前一条命令成功后,再执行后一条命令。这在生产环境中非常非常的重要! 以前经常听到段子,某某某在生产环境下一个误操作,误删了所有文件,你听到后可能第一反应是这人怎么会如此大意。但事实上,这种事情很有可能会发生在我们每个人身上!比如我们看下面一个脚本的命令:

$DIR=$( xxxx )
rm -rf $DIR

假设前面的命令,因此各种原因,偶然返回了错误结果,比如拼接字符串时发生了问题,返回了/, 那后面命令就变成了rm -rf /,如果这时这个脚本还直接用root权限来执行,那我只能建议你赶快跑路吧!但如果使用&&可以尽量避免前一条命令的失败后,继续执行后面缺少准备步骤的命令。

在脚本中,还可以通过加入set -e,实现命令失败时,脚本中断执行的效果。

  • 逻辑或运算符

有时,我们也会想在第一条命令失败时,再执行第二条命令。比如,原地址下载数据失败后,自动换一个镜像地址再下载:

wget ur1 || wget url2

逻辑运算符的组合基础是每个命令返回的状态符。我们可以简单理解成编程语言里面的函数,都会返回return truereturn false,通常在很多语言分别对应1和0。下载多个地址是实现是因为,逻辑或只需要其中一个为1(true)即可,只有原地址不成功(为0),才会执行第二条。逻辑或不仅能连接两条命令,还可以连接多条命令

  • 管道符

Linux的命令组合还有一个更加强大的用法,就是管道符|。管道符是把前一条命令的结果,作为下一条命令的输入。作为我们玩数据的小伙伴们,可能马上想到了,这和模型建模的多个子模型组合建模思路是何其相似啊!
比如,我们如果知识ps -ef是列出当前进行信息,而grep python是搜索含有python的文本内容,可以把这两条命令组合起来,寻找含有python信息的进程

ps -ef |grep python

通过管道符这种神奇的魔法,我们可以利用各个单独的小命令组合出一个完整复杂的命令。如果我们把单个命令看作一个个微小的独立服务,那么管道符的思想是不是和微服务有点异曲同工呢?

管道符的思想,在编程语言中一般通过函数嵌套的方式实现,即f2(f1()),或xxx.f1().f2().f3()。更加高级的管道符可以查阅R中的magrittr实现的%>%管道

  • 重定向操作符

Linux可以将命令结果用重定向操作符输出的指定目的。利用重定向操作符,我们就可以很方便的将当前目录的文件列表保存在一个txt中:

ls -l > filelist.txt

重定向>的结果输出每次会覆盖原文件内容,假如我们保存模型训练时的一些日记信息,这时就不希望覆盖,而是添加内容。这时,我们可以换用>>,内容会追加到目标文件中。

环境变量

Linux中有大量的环境变量,其中有几个系统环境经常使用:

语句作用举例
UID,GID在命令中,UID和GID表示为当前用户ID及其用户组ID,其值由系统自动赋值sudo chown $UID:$GID -R ./wheels
CUDA_VISIABLE_DEVICES控制程序可使用的GPU显卡设备,可以设置多个设备ID,逗号为分隔符CUDA_VISIABLE_DEVICES=0,1 python object_detection/legacy/train.py ...
PWD, OLDPWD在命令中,PWD和OLDPWD表示为当前目录及跳转前的目录位置,其值由系统自动赋值echo $PWD
PATH设置可执行文件的搜索路径,作用等同Windows的Pathexport PATH=PATH:/XXX
LD_LIBRARY_PATH动态库的搜索路径export LD_LIBRARY_PATH=LD_LIBRARY_PATH:/XXX
PYTHONPATHPython库搜索路径,设置后可以不安装就使用该位置的代码export PYTHONPATH=$PYTHONPATH:$PWD/research
HTTP_PROXY代理服务器的ip和端口号export http_proxy="http://127.0.0.1:8123"
一个被误解的变量

上述的环境变量中,我需要单独强调下LD_LIBRARY_PATH这个变量。因为至今为止,我都没见过几个真正理解这个变量的人!不管是Linux小白,还是有着开发经验数十年的所谓老鸟,都把这变量当成一个偷懒法宝,不断用在生产环境中。这导致,无数行业标杆的商业软件的配置手册里面,都会教你使用设置全局的LD_LIBRARY_PATH

简单来说,LD_LIBRARY_PATH的正确使用场景是软件测试时的临时变量。这个变量可以方便的让我们在当前窗口,临时测试一个软件库的效果。但是很多不负责任的人,却教你设置成全局,把这变量写到/etc/profile或者其他系统文件中。这会非常容易导致你的程序,被这个全局变量影响后,指向原本不兼容,甚至非法的库文件,导致程序崩溃或者其他错误问题。

Linux中有很多发行版本的开发者大神们,意识到这个问题的严重性。他们对自己发布的发行版做了改进,只要内核中发现在全局文件中存在这个变量,Linux内核会自动忽略这个变量。这本来是好事,但可惜这个世界上自作聪明或不知甚解的人太多,居然把这个当做是个bug,还要试图解决?大家可以网上随便搜索下,还真不少这样的贴子。什么Java中获取不到LD_LIBRARY_PATH,Ubuntu全局变量LD_LIBRARY_PATH失效的解决办法。

我见过有老鸟因为不懂这个问题,编译链接时不去用rpath指明库文件,而是铁了心要用LD_LIBRARY_PATH不成,用了各种恶心的方法“解决”了,从而让软件变的更加臃肿,配置复杂,不安全。关于这个变量为什么不好的更详细解释,英语好的同学可以直接看这个链接:

http://xahlee.info/UnixResource_dir/_/ldpath.html

想看中文的同学可以直接查阅最后推荐的相关资料的第一条。

环境变量的操作
  • 环境变量的读取

在上面的表格里,UIDGIDPWD,和OLDPWD是由系统自动赋值,我们只需要使用他们的值。这里注意在shell环境下,需要使用一个$前缀表示环境变量名,而在Makefile中,则需要写成$$前缀。比如,我们可以利用PWD变量,补全相对路径的全路径:

echo $PWD
echo $PWD/test.sh

其中,echo是显示命令,第一条是显示$PWD的值,即当前的目录位置。第二条则直接使用$PWD和后面的tesh.sh拼成完整的全路径。

上述例子中,使用$PWD拼接全路径是非常有意义的。这是因为,很多程序或脚本,由于各种原因,并不支持相对路径的写法。如果当前目录的路径太长,我们就可以利用$PWD快速拼接全路径。

另外,我们如果不确定环境变量是否设置成功,还可以通过env命令去查询:

env |grep -i proxy 

以上命令是查询当前环境中,所有包含proxy关键词的环境变量。

  • 环境变量的设置

我们可以使用export设置变量:

export http_proxy="http://127.0.0.1:8123"

其中,双引号的内容就是要设置是代理服务器ip和端口号。注意该export设置只在当前窗口的对话中起效。一旦新开窗口,变量值还原。如果想永久起效,就在相应的系统文件中写入export语句,比如/etc/profile,或者~/.bashrc中,前者是系统全局的配置文件,后者是当前用户的配置文件。但是,正如前述,不要这样设置LD_LIBRARY_PATH

另外,还可以在要执行的命令之前,加上环境变量=值这样的写法,比如临时设置可用的GPU:

CUDA_VISIABLE_DEVICES=2,1,0 python object_detection/legacy/train.py --logtostderr ...

上面语句,就是设置目标检测程序,可以使用2号,1号和0号这三张显卡。这种方式的变量作用域只在这一条命令生效

  • 环境变量的取消

假设我们在前面下载国外网站的数据时,设置了代理器。而当我们在当前命令行对话中,又要下载国内数据和软件包,会需要取消之前的设置,我们可以用unset命令:

unset http_proxy https_proxy

上述命令一次清除了多个环境变量,我们可以利用env命令来确认是否清除成功:

env |grep -i proxy 

总结

在今天的文章中,我们首先介绍了Linux命令行的基本概念,以及命令行的基本形式。通过对Linux权限、编码、包管理、命令连接和环境变量等几个方面的介绍,并引出与这些特点相关的常用的Linux命令。

在下篇中,我将通过场景实例方式,重点介绍命令行下,简单处理数据的命令方法,欢迎大家来学习,我们这个专栏成立了专门的读者交流群,我会在群里与大家一起来探讨学习这个专栏过程中遇到的问题。

加入方式:扫描下方的微信二维码,添加微信好友,之后统一邀请你加入交流群。添加好友时一定要备注:AI炼丹炉。 

640?wx_fmt=jpeg

相关资源

  • 为什么说 LD_LIBRARY_PATH 不好 - 三多 - CSDN 博客

    (https://blog.csdn.net/qpwyj/article/details/39835007)

  • 命令行中的数据科学 (豆瓣)

    (https://book.douban.com/subject/26387975/https://book.douban.com/subject/26387975/)

  • 鳥哥的 Linux 私房菜

    (http://linux.vbird.org/)


今天的内容很多,能坚持看到这里的你很优秀!为此,我准备了一个小彩蛋给大家。大部分人以为Linux只有黑漆漆的眼,哦不是,是黑漆漆的命令行,完全比不上Windows,甚至Mac系统来的华丽。对此,我表示完全不能认同,不信?!请看下面的视频(强烈推荐带上耳机来观看):




/ 今日赠送书籍 /


之后打算每天都赠送一本书籍给大家,获取方式为 混脸熟根据下面的 今日留言主题 去用心留言,我从最脸熟的读者中选出一位来赠送),留言的位置为AI派公众号当天发布文章的 头条或者次条,很多人不理解什么是头条和次条,我来举一个示例大家就明白了。

640?wx_fmt=jpeg


今天我们就是在“ 次条”留言来获取书籍的,今天的书籍为《Keras深度学习实战》。
640?wx_fmt=jpeg

本书简介:

这是一本实践性很强的深度学习工具书,既适合希望快速学习和使用Keras深度学习框架的工程师、学者和从业者,又特别适合立志从事深度学习和AI相关的行业并且希望用Keras开发实际项目的工程技术人员。

?↑↑扫描上方二维码可购买



恭喜上期通过留言成功混脸熟的读者:jane,赠送一本《从零开始学Python网络爬虫》

请该同学联系小编:wanglaoshi201908


640?wx_fmt=jpeg

/ 今日留言主题 /

你在使用Linux过程中都遇到过哪些坑?


近期专栏推荐


1. 算法原理稳如狗,工程落地慌得很!AI炼丹炉实践指南来啦~

2. 从0到1,数据分析师修炼之路

3. "王老湿,我。。我想学那个。。爬虫。可以嘛"

4. 想学机器学习吗?带坑的那种

640?wx_fmt=png


点下「在看」,给文章盖个戳吧! ?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值