TensorFlow技術(shù)內(nèi)幕(四):TF中的混合編程

本章的主題是TF中的混合編程挤渔,以Python與C/C++混合編程為例.

按進(jìn)度來(lái)說(shuō)阿逃,現(xiàn)在應(yīng)該寫(xiě)點(diǎn)TF使用教程逸绎,讓大家熟悉一下tensorflow的使用骡男,但是我發(fā)現(xiàn)現(xiàn)在這方面的資料和書(shū)籍已經(jīng)很多了淆游,這里就不再贅述了,畢竟時(shí)間有限,留給更有意義的事情犹菱。

做到熟悉TF使用的最好的方式就是動(dòng)手實(shí)踐具體的例子拾稳,官網(wǎng)提供的教程就不錯(cuò)。我建議繼續(xù)閱讀本章之前腊脱,讀者通過(guò)這些實(shí)際操作的例子访得,熟悉一下TensorFlow的使用流程。

下面進(jìn)入本章的主題陕凹。

連接兩個(gè)世界的傳送門(mén)

回憶上一章中悍抑,我們編譯、安裝tensorflow的方式如下:

首先捆姜,bazel build目標(biāo)

$ bazel build --config=opt //tensorflow/tools/pip_package:build_pip_package

然后传趾,啟動(dòng)目標(biāo)程序,生成wheel格式安裝包到tmp/tensorflow_pkg目錄:

$ bazel-bin/tensorflow/tools/pip_package/build_pip_package /tmp/tensorflow_pkg

最后泥技,通過(guò)tensorflow的pip包管理器安裝tensorflow的安裝包:

$ sudo pip install /tmp/tensorflow_pkg/tensorflow-1.6.0-py2-none-any.whl

這個(gè)流程我相信大家都已經(jīng)很熟悉了浆兰,我們就從這個(gè)頂級(jí)的構(gòu)建目標(biāo)入手,自頂向下分析TF中Python的調(diào)用是如何進(jìn)入C/C++世界的珊豹。

第二章中我們提到簸呈,上面命令中的構(gòu)建目標(biāo) //tensorflow/tools/pip_package:build_pip_package 其實(shí)是一個(gè)可執(zhí)行的 shell 腳本,通過(guò) bazel 的 sh_binary 規(guī)則生成店茶,sh_binary 的規(guī)則會(huì)將腳本依賴(lài)的文件拷貝或則生成(如果被依賴(lài)項(xiàng)也是bazel的規(guī)則定義的目標(biāo)的話(huà))到runfiles目錄下蜕便,腳本build_pip_package.sh的工作就是將這些文件打包成一個(gè)wheel格式的安裝包。

第一章中贩幻,我們學(xué)習(xí)到tf的內(nèi)核是由C++寫(xiě)成的轿腺,支持的前端API有Python,Go丛楚,Java族壳,這些前端語(yǔ)言接口基本都是對(duì)C API的封裝;那么我們把TF的整個(gè)工程分為兩個(gè)部門(mén)來(lái)分別學(xué)習(xí):接口部分和內(nèi)核部分趣些;我們還知道仿荆,接口部分通往內(nèi)核部分的最終都會(huì)通過(guò)//tensorflow/c:c_api。

因此坏平,我們來(lái)看下Python的頂級(jí)目標(biāo)與c_api的關(guān)系拢操。這里需要用到了 bazel 的query命令。

我們?cè)趖f工程根目錄執(zhí)行下面的命令:

$ bazel query  'allpaths(//tensorflow/tools/pip_package:build_pip_package, //tensorflow/c:c_api)' --output graph | dot -v -Tpng -o dep_paths.in

命令的作用是找到bazel目標(biāo) //tensorflow/tools/pip_package:build_pip_package 到目標(biāo) //tensorflow/c:c_api 的所有依賴(lài)路徑舶替,并將結(jié)果輸出為圖片:

圖3:build_pip_package到c_api的所以依賴(lài)路徑

這用到了graphviz的dot命令令境,graphviz的安裝也很簡(jiǎn)單:

$ sudo apt-get install graphviz

圖3是一個(gè)有向圖,每一條有向邊代表源節(jié)點(diǎn)對(duì)目的節(jié)點(diǎn)的依賴(lài)關(guān)系顾瞪,可以看到涉及的工程目標(biāo)非常多展父,依賴(lài)也繁雜返劲,但是還是可以分析的;首先栖茉,我們注意這兩個(gè)節(jié)點(diǎn):其中一個(gè)節(jié)點(diǎn)只有出度沒(méi)有入度,這就是我們都頂級(jí)構(gòu)建目標(biāo) //tensorflow/tools/pip_package:build_pip_package

圖4:build_pip_package 節(jié)點(diǎn)

<center>圖4:build_pip_package 節(jié)點(diǎn)</center>

另一個(gè)節(jié)點(diǎn)只有入度孵延,沒(méi)有出度吕漂,就是我們的 //tensorflow/c:c_api 節(jié)點(diǎn):

圖5:c_api節(jié)點(diǎn)

<center>圖5:c_api節(jié)點(diǎn)</center>

另外,還有一個(gè)節(jié)點(diǎn)比較引人注意尘应,那就是 //tensorflow/python:pywrap_tensorflow_internal惶凝,我們注意到這樣一個(gè)特征,整張圖在這個(gè)節(jié)點(diǎn)上分成了上下兩個(gè)"團(tuán)體"犬钢,每個(gè)團(tuán)體內(nèi)部的依賴(lài)比較復(fù)雜苍鲜,暫時(shí)先不用管,但是上層"團(tuán)體"對(duì)下層"團(tuán)體"的依賴(lài)都經(jīng)過(guò)//tensorflow/python:pywrap_tensorflow_internal節(jié)點(diǎn):

圖6:pywrap_tensorflow_internal

<center>圖6:pywrap_tensorflow_internal</center>

直觀感覺(jué)玷犹,這個(gè)節(jié)點(diǎn)至關(guān)重要混滔,是連接了兩個(gè)世界的"傳送門(mén)"。

Python擴(kuò)展pywrap_tensorflow_internal

找到定義pywrap_tensorflow_internal的BUILD文件//tensorflow/python/BUILD:

tf_py_wrap_cc(
    name = "pywrap_tensorflow_internal",
    srcs = ["tensorflow.i"],
    swig_includes = [
        "client/device_lib.i",
        "client/events_writer.i",
        "client/tf_session.i",
        "client/tf_sessionrun_wrapper.i",
        "framework/cpp_shape_inference.i",
        "framework/python_op_gen.i",
        "grappler/cost_analyzer.i",
        "grappler/tf_optimizer.i",
        "lib/core/py_func.i",
        "lib/core/strings.i",
        "lib/io/file_io.i",
        "lib/io/py_record_reader.i",
        "lib/io/py_record_writer.i",
        "platform/base.i",
        "training/quantize_training.i",
        "training/server_lib.i",
        "util/kernel_registry.i",
        "util/port.i",
        "util/py_checkpoint_reader.i",
        "util/stat_summarizer.i",
        "util/transform_graph.i",
    ],
    deps = [
        ":cost_analyzer_lib",
        ":cpp_shape_inference",
        ":kernel_registry",
        ":numpy_lib",
        ":py_func_lib",
        ":py_record_reader_lib",
        ":py_record_writer_lib",
        ":python_op_gen",
        ":tf_session_helper",
        "http://tensorflow/c:c_api",
        "http://tensorflow/c:checkpoint_reader",
        "http://tensorflow/c:tf_status_helper",
        "http://tensorflow/core/distributed_runtime/rpc:grpc_server_lib",
        "http://tensorflow/core/distributed_runtime/rpc:grpc_session",
        "http://tensorflow/core/grappler:grappler_item",
        "http://tensorflow/core/grappler:grappler_item_builder",
        "http://tensorflow/core/grappler/clusters:single_machine",
        "http://tensorflow/core/grappler/optimizers:meta_optimizer",
        "http://tensorflow/core:lib",
        "http://tensorflow/core:reader_base",
        "http://tensorflow/core/debug",
        "http://tensorflow/core/distributed_runtime:server_lib",
        "http://tensorflow/tools/graph_transforms:transform_graph_lib",
        "http://tensorflow/tools/tfprof/internal:print_model_analysis",
        "http://util/python:python_headers",
    ] + (tf_additional_lib_deps() +
         tf_additional_plugin_deps() +
         tf_additional_verbs_deps() +
         tf_additional_mpi_deps()),
)

這里的tf_py_wrap_cc是bazel的宏函數(shù)歹颓。那么宏函數(shù)tf_py_wrap_cc的作用是什么坯屿?這里srcs和swig_includes屬性里的擴(kuò)展名為 .i 文件又是什么呢?

找到宏函數(shù)tf_py_wrap_cc定義的文件 /tensorflow/tensorflow.bzl :

def tf_py_wrap_cc(name,
                             srcs,
                             swig_includes=[],
                             deps=[],
                             copts=[],
                             **kwargs):
  module_name = name.split("/")[-1]
  # Convert a rule name such as foo/bar/baz to foo/bar/_baz.so
  # and use that as the name for the rule producing the .so file.
  cc_library_name = "/".join(name.split("/")[:-1] + ["_" + module_name + ".so"])
  cc_library_pyd_name = "/".join(
      name.split("/")[:-1] + ["_" + module_name + ".pyd"])
  extra_deps = []
  _py_wrap_cc(
      name=name + "_py_wrap",
      srcs=srcs,
      swig_includes=swig_includes,
      deps=deps + extra_deps,
      toolchain_deps=["http://tools/defaults:crosstool"],
      module_name=module_name,
      py_module_name=name)
   ... 
   ...

函數(shù)的前半部分巍扛,主要就是調(diào)用一個(gè)自定義規(guī)則 _py_wrap_cc领跛,此規(guī)則聲明同在tensorflow/tensorflow.bzl文件中,內(nèi)容如下:

_py_wrap_cc = rule(
    #
    # 定義規(guī)則的輸入屬性名稱(chēng)撤奸,數(shù)據(jù)類(lèi)型吠昭,是否必須以及默認(rèn)值等
    #
    attrs={
        "srcs":
            attr.label_list(
                mandatory=True,
                allow_files=True,),
        "swig_includes":
            attr.label_list(
                cfg="data",
                allow_files=True,),
        "deps":
            attr.label_list(
                allow_files=True,
                providers=["cc"],),
        "toolchain_deps":
            attr.label_list(
                allow_files=True,),
        "module_name":
            attr.string(mandatory=True),
        "py_module_name":
            attr.string(mandatory=True),
        "_swig":
            attr.label(
                default=Label("@swig//:swig"),
                executable=True,
                cfg="host",),
        "_swiglib":
            attr.label(
                default=Label("@swig//:templates"),
                allow_files=True,),
    },
    
    #
    # 定義規(guī)則的輸出
    #
    outputs={
        "cc_out": "%{module_name}.cc",
        "py_out": "%{py_module_name}.py",
    },
    
    #
    # 定義規(guī)則的實(shí)現(xiàn)函數(shù)
    #
    implementation=_py_wrap_cc_impl,)

規(guī)則聲明中,定義了規(guī)則的屬性胧瓜、屬性的變量類(lèi)型以及默認(rèn)取值矢棚、規(guī)則的輸出以及實(shí)現(xiàn)函數(shù);_py_wrap_cc規(guī)則的實(shí)現(xiàn)在函數(shù)_py_wrap_cc_impl中贷痪,我們將仔細(xì)分析一下這個(gè)函數(shù)幻妓。

注:宏函數(shù)和自定義規(guī)則是bazel支持的兩個(gè)擴(kuò)展機(jī)制,兩則是有差別的劫拢,
限于篇幅這里就不仔細(xì)介紹了肉津。可以參考
[官網(wǎng)](https://docs.bazel.build/versions/master/skylark/concepts.html)舱沧。
暫時(shí)讀者只要能更隨本人思路就可以妹沙,細(xì)節(jié)可以之后再去學(xué)習(xí),本人盡力保證在讀者不熟悉bazel
的情況下也能理解本文內(nèi)容熟吏。

在詳細(xì)分析_py_wrap_cc_impl函數(shù)之前距糖,我們需要補(bǔ)充一點(diǎn)關(guān)于Python和C/C++混合編程的知識(shí)玄窝。

SWIG

圖7:Python與C/C++混合編程的兩種模式

Python和C/C++的混合編程存在兩種編程模式:擴(kuò)展與嵌入,這里主要介紹前一種悍引。C/C++編寫(xiě)Pyton擴(kuò)展過(guò)程如下:

圖8:第一步恩脂、編寫(xiě)封裝函數(shù)
圖9:第二步、編寫(xiě)模塊初始話(huà)函數(shù)
圖10:完整的擴(kuò)展例子

可以看到趣斤,手動(dòng)完成擴(kuò)展的編寫(xiě)還是挺低效的俩块,最后還需要將編寫(xiě)完的封裝代碼和源碼一起編譯成動(dòng)態(tài)鏈接庫(kù),限于篇幅浓领,這里就不具體介紹了玉凯;我們來(lái)介紹一個(gè)自動(dòng)化完成擴(kuò)展編寫(xiě)的工具SWIG。

圖11:swig簡(jiǎn)介

SWIG是一個(gè)接口編譯工具联贩,連接C/C++代碼與腳本語(yǔ)言Perl.Python,Ruby,Tcl的橋梁漫仆。SWIG為C/C++頭文件自動(dòng)生成包裝代碼,提供給腳本語(yǔ)言使用泪幌。

我們來(lái)看一個(gè)例子盲厌,假如我們有這樣一個(gè)C代碼文件example.c,其中包含了想要提供給其他語(yǔ)言如Perl,Python,java,C#代碼使用的方法:

/* File : example.c */
 
 #include <time.h>
 double My_variable = 3.0;
 
 int fact(int n) {
     if (n <= 1) return 1;
     else return n*fact(n-1);
 }
 
 int my_mod(int x, int y) {
     return (x%y);
 }
    
 char *get_time()
 {
     time_t ltime;
     time(&ltime);
     return ctime(&ltime);
 }

那么首先我們需要?jiǎng)?chuàng)建一個(gè)"接口文件"座菠,擴(kuò)展名為 .i:

/* example.i */
%module example
%{
/* Put header files here or function declarations like below */
extern double  My_variable;
extern int fact(int n);
extern int my_mod(int x, int y);
extern char *get_time();
%}

extern double My_variable;
extern int fact(int n);
extern int my_mod(int x, int y);
extern char *get_time();

然后就可以構(gòu)建其他語(yǔ)言的模塊了狸眼,例如可以執(zhí)行如下命令構(gòu)建Python模塊:

$ swig -python example.i
$ gcc -c example.c example_wrap.c -I/usr/local/include/python2.1
$ ld -shared example.o example_wrap.o -o _example.so

然后就可以調(diào)用生成的Python模塊了:

>>> import example
>>> example.fact(5)
120
>>> example.my_mod(7,3)
1
>>> example.get_time()
'Sun Feb 11 23:01:07 1996'
>>>

可以通過(guò)執(zhí)行下列命令生成Java模塊:

$ swig -java example.i
$ gcc -c example.c example_wrap.c -I/c/jdk1.3.1/include -I/c/jdk1.3.1/include/win32
$ gcc -shared example.o example_wrap.o -mno-cygwin -Wl, --add-stdcall-alias -o example.dll

然后可以編寫(xiě)java代碼,調(diào)用此模塊:

/* file main.java */

public class main{
    public static void main(String argv[]){
        System.loadLobrary('example');
        System.out.println(example.getMy_variable());
        System.out.println(example.fact(5));
        System.out.println(example.get_time());
    }
}

最后執(zhí)行調(diào)用:

$ javac main.java
$ java main
3.0
120
Mon Mar  4 18:20:31  2002
$

有了這些準(zhǔn)備知識(shí)后浴滴,我們可以開(kāi)始分析_py_wrap_cc_impl函數(shù)了:

# Bazel rules for building swig files.
def _py_wrap_cc_impl(ctx):

  ##
  ## 下面的代碼在構(gòu)造SWIG的參數(shù)
  ##
  srcs = ctx.files.srcs
  if len(srcs) != 1:
    fail("Exactly one SWIG source file label must be specified.", "srcs")
  module_name = ctx.attr.module_name
  src = ctx.files.srcs[0]
  inputs = set([src])
  inputs += ctx.files.swig_includes
  for dep in ctx.attr.deps:
    inputs += dep.cc.transitive_headers
  inputs += ctx.files._swiglib
  inputs += ctx.files.toolchain_deps
  swig_include_dirs = set(_get_repository_roots(ctx, inputs))
  swig_include_dirs += sorted([f.dirname for f in ctx.files._swiglib])
  
  ##
  ## swig的命令行參數(shù):-c++表示啟動(dòng)C++解析拓萌,-python表示輸出python的
  ## wrapper代碼,-module設(shè)置模塊名稱(chēng)升略,-o表示輸出文件名稱(chēng)微王,-outdir
  ## 表示輸出目錄路徑,-l表示包含的SWIG的庫(kù)文件名稱(chēng)品嚣,包括用戶(hù)提供的.i文件
  ## 以及需要的SWIG庫(kù)文件(也是一些.i文件)炕倘,-I表示把參數(shù)路徑添
  ## 加到SWIG的include查找路徑耍休。
  ## 
  args = [
      "-c++", "-python", "-module", module_name, "-o", ctx.outputs.cc_out.path,
      "-outdir", ctx.outputs.py_out.dirname
  ]
  args += ["-l" + f.path for f in ctx.files.swig_includes]
  args += ["-I" + i for i in swig_include_dirs]
  args += [src.path]
  outputs = [ctx.outputs.cc_out, ctx.outputs.py_out]
  
  ##
  ## 調(diào)用SWIG命令吵聪,生成swig files:ctx.action函數(shù)會(huì)啟動(dòng)一個(gè)
  ## 可執(zhí)行文件或腳本executable, 啟動(dòng)參數(shù)arguments, inputs
  ## 表示表示輸入文件芯杀,outputs表示輸出文件颜懊。
  ##
  ctx.action(
      executable=ctx.executable._swig,
      arguments=args,
      inputs=list(inputs),
      outputs=outputs,
      mnemonic="PythonSwig",
      progress_message="SWIGing " + src.path)
  return struct(files=set(outputs))

C/C++的Python插件封裝代碼通過(guò)SWIG生成之后,就可以編譯Python的插件了聂宾,這就是函數(shù)tf_py_wrap_cc后半部分所完成的工作:

def tf_py_wrap_cc(name,
                             srcs,
                             swig_includes=[],
                             deps=[],
                             copts=[],
                             **kwargs):
    ...
    ...
    ## 
    ## module_name + ".cc"是上面介紹的_py_wrap_cc規(guī)則的輸出文件
    ## 也就是C/C++代碼的Python封裝代碼友题,與dep中的C/C++代碼一起郁季,
    ## 通過(guò)cc_binary規(guī)則逝撬,生成動(dòng)態(tài)鏈接庫(kù)cc_library_name浴骂。
    ##
    native.cc_binary(
      name=cc_library_name,
      srcs=[module_name + ".cc"],
      copts=(copts + [
          "-Wno-self-assign", "-Wno-sign-compare", "-Wno-write-strings"
      ] + tf_extension_copts()),
      linkopts=tf_extension_linkopts() + extra_linkopts,
      linkstatic=1,
      linkshared=1,
      deps=deps + extra_deps)
      
  ##
  ## 定義一個(gè)生成規(guī)則,執(zhí)行拷貝命令cp宪潮,將動(dòng)態(tài)鏈接庫(kù)cc_library_name拷貝一份溯警,
  ## 名稱(chēng)為cc_library_pyd_name(python的pyd文件實(shí)際也就是windows平臺(tái)下動(dòng)態(tài)鏈接庫(kù)趣苏,
  ## 只不過(guò)擴(kuò)展名不一樣而已)
  ##
  native.genrule(
      name="gen_" + cc_library_pyd_name,
      srcs=[":" + cc_library_name],
      outs=[cc_library_pyd_name],
      cmd="cp $< $@",)
      
  ##
  ## py_library規(guī)則定義一個(gè)python庫(kù)目標(biāo),如果是windows平臺(tái)下
  ## 則依賴(lài).pyd文件cc_library_pyd_name梯轻,這會(huì)出發(fā)上面的拷貝動(dòng)作食磕,其他
  ## 平臺(tái)下,則依賴(lài).so文件cc_library_name
  native.py_library(
      name=name,
      srcs=[":" + name + ".py"],
      srcs_version="PY2AND3",
      data=select({
          clean_dep("http://tensorflow:windows"): [":" + cc_library_pyd_name],
          "http://conditions:default": [":" + cc_library_name],
      }))

最后喳挑,執(zhí)行bazel build命令芬为,在windows下,會(huì)生成下列文件:

pywrap_tensorflow_internal.cc
pywrap_tensorflow_internal.py
_pywrap_tensorflow_internal.pyd

而在非window平臺(tái)下蟀悦,則生成下列文件:

pywrap_tensorflow_internal.cc
pywrap_tensorflow_internal.py
_pywrap_tensorflow_internal.so

小結(jié)

總結(jié)一下,本章中氧敢,我們通過(guò)工具bazel query,找到了混合編程中鏈接兩個(gè)世界的模塊pywrap_tensorflow_internal日戈,實(shí)際上它就是Python的一個(gè)擴(kuò)展,python的代碼通過(guò)這個(gè)擴(kuò)展就可以調(diào)用底層的C/C++代碼了孙乖。然后分析此工程的過(guò)程中浙炼,引入了SWIG工具,它使得C/C++代碼很方便的導(dǎo)出到各種其他的腳本語(yǔ)言唯袄。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末弯屈,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子恋拷,更是在濱河造成了極大的恐慌资厉,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,214評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蔬顾,死亡現(xiàn)場(chǎng)離奇詭異宴偿,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)诀豁,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén)窄刘,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人舷胜,你說(shuō)我怎么就攤上這事娩践。” “怎么了烹骨?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,543評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵翻伺,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我展氓,道長(zhǎng)穆趴,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,221評(píng)論 1 279
  • 正文 為了忘掉前任遇汞,我火速辦了婚禮未妹,結(jié)果婚禮上簿废,老公的妹妹穿的比我還像新娘。我一直安慰自己络它,他們只是感情好族檬,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,224評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著化戳,像睡著了一般单料。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上点楼,一...
    開(kāi)封第一講書(shū)人閱讀 49,007評(píng)論 1 284
  • 那天扫尖,我揣著相機(jī)與錄音,去河邊找鬼掠廓。 笑死换怖,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的蟀瞧。 我是一名探鬼主播沉颂,決...
    沈念sama閱讀 38,313評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼悦污!你這毒婦竟也來(lái)了铸屉?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 36,956評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤切端,失蹤者是張志新(化名)和其女友劉穎彻坛,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體帆赢,經(jīng)...
    沈念sama閱讀 43,441評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡小压,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,925評(píng)論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了椰于。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片怠益。...
    茶點(diǎn)故事閱讀 38,018評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖瘾婿,靈堂內(nèi)的尸體忽然破棺而出蜻牢,到底是詐尸還是另有隱情,我是刑警寧澤偏陪,帶...
    沈念sama閱讀 33,685評(píng)論 4 322
  • 正文 年R本政府宣布抢呆,位于F島的核電站,受9級(jí)特大地震影響笛谦,放射性物質(zhì)發(fā)生泄漏抱虐。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,234評(píng)論 3 307
  • 文/蒙蒙 一饥脑、第九天 我趴在偏房一處隱蔽的房頂上張望恳邀。 院中可真熱鬧懦冰,春花似錦、人聲如沸谣沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,240評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)乳附。三九已至内地,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間赋除,已是汗流浹背阱缓。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,464評(píng)論 1 261
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留举农,地道東北人茬祷。 一個(gè)月前我還...
    沈念sama閱讀 45,467評(píng)論 2 352
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像并蝗,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子秸妥,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,762評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容

  • 網(wǎng)址 下載與安裝 你可以使用我們提供的 Pip, Docker, Virtualenv, Anaconda 或 源...
    九七學(xué)姐閱讀 4,734評(píng)論 3 11
  • 安裝tensorflow 下載tensorflow源文件 Gitclone--recurse-submodules...
    風(fēng)果閱讀 1,932評(píng)論 0 2
  • 1. 介紹 首先讓我們來(lái)看看TensorFlow滚停! 但是在我們開(kāi)始之前,我們先來(lái)看看Python API中的Ten...
    JasonJe閱讀 11,721評(píng)論 1 32
  • 車(chē)在夜路上飛速行駛著粥惧。 車(chē)內(nèi)安靜平穩(wěn)键畴。副駕駛座上的我百無(wú)聊賴(lài),索性對(duì)著鏡子整理妝容突雪,將兩片薄唇的紅加深了一層起惕。...
    肖夢(mèng)芹閱讀 390評(píng)論 0 2
  • 白瓷圈上黃跡斑斑點(diǎn)點(diǎn) 無(wú)數(shù)雞巴晃蕩后的杰作 女人永遠(yuǎn)不會(huì)這種創(chuàng)作 她們真是優(yōu)雅 光這一點(diǎn)我就熱愛(ài)她們 紳士也優(yōu)雅地...
    中習(xí)習(xí)閱讀 248評(píng)論 0 1