gnu: Add tensorflow.

* gnu/packages/machine-learning.scm (tensorflow): New variable.
This commit is contained in:
Ricardo Wurmus 2019-04-08 14:45:47 +02:00 committed by Ricardo Wurmus
parent d0a39b928c
commit 4fa16c9ae6
No known key found for this signature in database
GPG Key ID: 197A5888235FACAC

View File

@ -49,6 +49,7 @@
#:use-module (gnu packages check)
#:use-module (gnu packages compression)
#:use-module (gnu packages cran)
#:use-module (gnu packages databases)
#:use-module (gnu packages dejagnu)
#:use-module (gnu packages gcc)
#:use-module (gnu packages glib)
@ -65,7 +66,9 @@
#:use-module (gnu packages python)
#:use-module (gnu packages python-web)
#:use-module (gnu packages python-xyz)
#:use-module (gnu packages serialization)
#:use-module (gnu packages statistics)
#:use-module (gnu packages sqlite)
#:use-module (gnu packages swig)
#:use-module (gnu packages tls)
#:use-module (gnu packages web)
@ -1303,3 +1306,451 @@ for load balancing, tracing, health checking and authentication. It is also
applicable in last mile of distributed computing to connect devices, mobile
applications and browsers to backend services.")
(license license:asl2.0)))
;; Note that Tensorflow includes a "third_party" directory, which seems to not
;; only contain modified subsets of upstream library source code, but also
;; adapter headers provided by Google (such as the fft.h header, which is not
;; part of the upstream project code). The Tensorflow code includes headers
;; from the "third_party" directory. It does not look like we can replace
;; these headers with unmodified upstream files, so we keep them.
(define-public tensorflow
(package
(name "tensorflow")
(version "1.9.0")
(source
(origin
(method git-fetch)
(uri (git-reference
(url "https://github.com/tensorflow/tensorflow.git")
(commit (string-append "v" version))))
(file-name (string-append "tensorflow-" version "-checkout"))
(sha256
(base32
"0a9kwha395g3wgxfwln5j8vn9nkspmd75xldrlqdq540w996g8xa"))))
(build-system cmake-build-system)
(arguments
`(#:tests? #f ; no "check" target
#:build-type "Release"
#:configure-flags
(let ((protobuf (assoc-ref %build-inputs "protobuf"))
(protobuf:native (assoc-ref %build-inputs "protobuf:native"))
(jsoncpp (assoc-ref %build-inputs "jsoncpp"))
(snappy (assoc-ref %build-inputs "snappy"))
(sqlite (assoc-ref %build-inputs "sqlite")))
(list
;; Use protobuf from Guix
(string-append "-Dprotobuf_STATIC_LIBRARIES="
protobuf "/lib/libprotobuf.so")
(string-append "-DPROTOBUF_PROTOC_EXECUTABLE="
protobuf:native "/bin/protoc")
;; Use snappy from Guix
(string-append "-Dsnappy_STATIC_LIBRARIES="
snappy "/lib/libsnappy.so")
;; Yes, this is not actually the include directory but a prefix...
(string-append "-Dsnappy_INCLUDE_DIR=" snappy)
;; Use jsoncpp from Guix
(string-append "-Djsoncpp_STATIC_LIBRARIES="
jsoncpp "/lib/libjsoncpp.so")
;; Yes, this is not actually the include directory but a prefix...
(string-append "-Djsoncpp_INCLUDE_DIR=" jsoncpp)
;; Use sqlite from Guix
(string-append "-Dsqlite_STATIC_LIBRARIES="
sqlite "/lib/libsqlite.a")
;; Use system libraries wherever possible. Currently, this
;; only affects zlib.
"-Dsystemlib_ALL=ON"
"-Dtensorflow_ENABLE_POSITION_INDEPENDENT_CODE=ON"
"-Dtensorflow_BUILD_SHARED_LIB=ON"
"-Dtensorflow_OPTIMIZE_FOR_NATIVE_ARCH=OFF"
"-Dtensorflow_ENABLE_SSL_SUPPORT=OFF"
"-Dtensorflow_BUILD_CONTRIB_KERNELS=OFF"))
#:make-flags
(list "CC=gcc")
#:modules ((ice-9 ftw)
(guix build utils)
(guix build cmake-build-system))
#:phases
(modify-phases %standard-phases
(add-after 'unpack 'set-source-file-times-to-1980
;; At the end of the tf_python_build_pip_package target, a ZIP
;; archive should be generated via bdist_wheel, but it fails with
;; "ZIP does not support timestamps before 1980". Luckily,
;; SOURCE_DATE_EPOCH is respected, which we set to some time in
;; 1980.
(lambda _ (setenv "SOURCE_DATE_EPOCH" "315532800") #t))
;; See https://github.com/tensorflow/tensorflow/issues/20517#issuecomment-406373913
(add-after 'unpack 'python3.7-compatibility
(lambda _
(substitute* '("tensorflow/python/eager/pywrap_tfe_src.cc"
"tensorflow/python/lib/core/ndarray_tensor.cc"
"tensorflow/python/lib/core/py_func.cc")
(("PyUnicode_AsUTF8") "(char *)PyUnicode_AsUTF8"))
(substitute* "tensorflow/c/eager/c_api.h"
(("unsigned char async")
"unsigned char is_async"))
;; Remove dependency on tensorboard, a complicated but probably
;; optional package.
(substitute* "tensorflow/tools/pip_package/setup.py"
((".*'tensorboard >.*") ""))
#t))
(add-after 'python3.7-compatibility 'chdir
(lambda _ (chdir "tensorflow/contrib/cmake") #t))
(add-after 'chdir 'disable-downloads
(lambda* (#:key inputs #:allow-other-keys)
(substitute* (find-files "external" "\\.cmake$")
(("GIT_REPOSITORY.*") "")
(("GIT_TAG.*") "")
(("PREFIX ")
"DOWNLOAD_COMMAND \"\"\nPREFIX "))
;; Use packages from Guix
(let ((grpc (assoc-ref inputs "grpc")))
(substitute* "CMakeLists.txt"
;; Sqlite
(("include\\(sqlite\\)") "")
(("\\$\\{sqlite_STATIC_LIBRARIES\\}")
(string-append (assoc-ref inputs "sqlite")
"/lib/libsqlite3.so"))
(("sqlite_copy_headers_to_destination") "")
;; PNG
(("include\\(png\\)") "")
(("\\$\\{png_STATIC_LIBRARIES\\}")
(string-append (assoc-ref inputs "libpng")
"/lib/libpng16.so"))
(("png_copy_headers_to_destination") "")
;; JPEG
(("include\\(jpeg\\)") "")
(("\\$\\{jpeg_STATIC_LIBRARIES\\}")
(string-append (assoc-ref inputs "libjpeg")
"/lib/libjpeg.so"))
(("jpeg_copy_headers_to_destination") "")
;; GIF
(("include\\(gif\\)") "")
(("\\$\\{gif_STATIC_LIBRARIES\\}")
(string-append (assoc-ref inputs "giflib")
"/lib/libgif.so"))
(("gif_copy_headers_to_destination") "")
;; lmdb
(("include\\(lmdb\\)") "")
(("\\$\\{lmdb_STATIC_LIBRARIES\\}")
(string-append (assoc-ref inputs "lmdb")
"/lib/liblmdb.so"))
(("lmdb_copy_headers_to_destination") "")
;; Protobuf
(("include\\(protobuf\\)") "")
(("protobuf_copy_headers_to_destination") "")
(("^ +protobuf") "")
;; gRPC
(("include\\(grpc\\)")
"find_package(grpc REQUIRED NAMES gRPC)")
(("list\\(APPEND tensorflow_EXTERNAL_DEPENDENCIES grpc\\)") "")
;; Eigen
(("include\\(eigen\\)")
(string-append "find_package(eigen REQUIRED NAMES Eigen3)
set(eigen_INCLUDE_DIRS ${CMAKE_CURRENT_BINARY_DIR}/external/eigen_archive "
(assoc-ref inputs "eigen") "/include/eigen3)"))
(("^ +eigen") "")
;; snappy
(("include\\(snappy\\)")
"add_definitions(-DTF_USE_SNAPPY)")
(("list\\(APPEND tensorflow_EXTERNAL_DEPENDENCIES snappy\\)") "")
;; jsoncpp
(("include\\(jsoncpp\\)") "")
(("^ +jsoncpp") ""))
(substitute* "tf_core_framework.cmake"
((" grpc") "")
(("\\$\\{GRPC_BUILD\\}/grpc_cpp_plugin")
(which "grpc_cpp_plugin"))
;; Link with gRPC libraries
(("add_library\\(tf_protos_cc.*" m)
(string-append m
(format #f "\ntarget_link_libraries(tf_protos_cc PRIVATE \
~a/lib/libgrpc++_unsecure.a \
~a/lib/libgrpc_unsecure.a \
~a/lib/libaddress_sorting.a \
~a/lib/libgpr.a \
~a//lib/libcares.so
)\n"
grpc grpc grpc grpc
(assoc-ref inputs "c-ares"))))))
(substitute* "tf_tools.cmake"
(("add_dependencies\\(\\$\\{proto_text.*") ""))
;; Remove dependency on bundled grpc
(substitute* "tf_core_distributed_runtime.cmake"
(("tf_core_cpu grpc") "tf_core_cpu"))
;; This directory is a dependency of many targets.
(mkdir-p "protobuf")
#t))
(add-after 'configure 'unpack-third-party-sources
(lambda* (#:key inputs #:allow-other-keys)
;; This is needed to configure bundled packages properly.
(setenv "CONFIG_SHELL" (which "bash"))
(for-each
(lambda (name)
(let* ((what (assoc-ref inputs (string-append name "-src")))
(name* (string-map (lambda (c)
(if (char=? c #\-)
#\_ c)) name))
(where (string-append "../build/" name* "/src/" name*)))
(cond
((string-suffix? ".zip" what)
(mkdir-p where)
(with-directory-excursion where
(invoke "unzip" what)))
((string-suffix? ".tar.gz" what)
(mkdir-p where)
(invoke "tar" "xf" what
"-C" where "--strip-components=1"))
(else
(let ((parent (dirname where)))
(mkdir-p parent)
(with-directory-excursion parent
(when (file-exists? name*)
(delete-file-recursively name*))
(copy-recursively what name*)
(map make-file-writable
(find-files name* ".*"))))))))
(list "boringssl"
"cub"
"double-conversion"
"farmhash"
"fft2d"
"highwayhash"
"nsync"
"re2"))
(rename-file "../build/cub/src/cub/cub-1.8.0/"
"../build/cub/src/cub/cub/")
#t))
(add-after 'unpack 'fix-python-build
(lambda* (#:key inputs outputs #:allow-other-keys)
(mkdir-p "protobuf-src")
(invoke "tar" "xf" (assoc-ref inputs "protobuf:src")
"-C" "protobuf-src" "--strip-components=1")
(mkdir-p "eigen-src")
(invoke "tar" "xf" (assoc-ref inputs "eigen:src")
"-C" "eigen-src" "--strip-components=1")
(substitute* "tensorflow/contrib/cmake/tf_python.cmake"
;; Ensure that all Python dependencies can be found at build time.
(("PYTHONPATH=\\$\\{CMAKE_CURRENT_BINARY_DIR\\}/tf_python" m)
(string-append m ":" (getenv "PYTHONPATH")))
;; Take protobuf source files from our source package.
(("\\$\\{CMAKE_CURRENT_BINARY_DIR\\}/protobuf/src/protobuf/src/google")
(string-append (getcwd) "/protobuf-src/src/google")))
(substitute* '("tensorflow/contrib/cmake/tf_shared_lib.cmake"
"tensorflow/contrib/cmake/tf_python.cmake")
;; Take Eigen source files from our source package.
(("\\$\\{CMAKE_CURRENT_BINARY_DIR\\}/eigen/src/eigen/")
(string-append (getcwd) "/eigen-src/"))
;; Take Eigen headers from our own package.
(("\\$\\{CMAKE_CURRENT_BINARY_DIR\\}/external/eigen_archive")
(string-append (assoc-ref inputs "eigen") "/include/eigen3")))
;; Correct the RUNPATH of ops libraries generated for Python.
;; TODO: this doesn't work :(
;; /gnu/store/...-tensorflow-1.9.0/lib/python3.7/site-packages/tensorflow/contrib/seq2seq/python/ops/lib_beam_search_ops.so:
;; warning: RUNPATH contains bogus entries: ("/tmp/guix-build-tensorflow-1.9.0.drv-0/source/tensorflow/contrib/build")
;; /gnu/store/...-tensorflow-1.9.0/lib/python3.7/site-packages/tensorflow/contrib/seq2seq/python/ops/lib_beam_search_ops.so:
;; error: depends on 'libpywrap_tensorflow_internal.so', which
;; cannot be found in RUNPATH ...
(substitute* "tensorflow/contrib/cmake/tf_cc_ops.cmake"
(("set_target_properties.*")
(string-append "set_target_properties(${_AT_TARGET} PROPERTIES \
COMPILE_FLAGS ${target_compile_flags} \
INSTALL_RPATH_USE_LINK_PATH TRUE \
INSTALL_RPATH " (assoc-ref outputs "out") "/lib)\n")))
#t))
(add-after 'build 'build-pip-package
(lambda* (#:key outputs #:allow-other-keys)
(setenv "LDFLAGS"
(string-append "-Wl,-rpath="
(assoc-ref outputs "out") "/lib"))
(invoke "make" "tf_python_build_pip_package")
#t))
(add-after 'build-pip-package 'install-python
(lambda* (#:key outputs #:allow-other-keys)
(let ((out (assoc-ref outputs "out"))
(wheel (car (find-files "../build/tf_python/dist/" "\\.whl$"))))
(invoke "python" "-m" "pip" "install" wheel
(string-append "--prefix=" out))
;; XXX: broken RUNPATH, see fix-python-build phase.
(delete-file
(string-append
out "/lib/python3.7/site-packages/tensorflow/contrib/"
"seq2seq/python/ops/lib_beam_search_ops.so"))
#t))))))
(native-inputs
`(("pkg-config" ,pkg-config)
("protobuf:native" ,protobuf-next) ; protoc
("protobuf:src" ,(package-source protobuf-next))
("eigen:src" ,(package-source eigen-for-tensorflow))
;; The commit hashes and URLs for third-party source code are taken
;; from "tensorflow/workspace.bzl".
("boringssl-src"
,(let ((commit "ee7aa02")
(revision "1"))
(origin
(method git-fetch)
(uri (git-reference
(url "https://boringssl.googlesource.com/boringssl")
(commit commit)))
(file-name (string-append "boringssl-0-" revision
(string-take commit 7)
"-checkout"))
(sha256
(base32
"1jf693q0nw0adsic6cgmbdx6g7wr4rj4vxa8j1hpn792fqhd8wgw")))))
("cub-src"
,(let ((version "1.8.0"))
(origin
(method url-fetch)
(uri (string-append "https://mirror.bazel.build/github.com/NVlabs/"
"cub/archive/" version ".zip"))
(file-name (string-append "cub-" version ".zip"))
(sha256
(base32
"1hsqikqridb90dkxkjr2918dcry6pfh46ccnwrzawl56aamhdykb")))))
("double-conversion-src"
,(let ((commit "5664746")
(revision "1"))
(origin
(method git-fetch)
(uri (git-reference
(url "https://github.com/google/double-conversion.git")
(commit commit)))
(file-name
(git-file-name "double-conversion"
(string-append "0-" revision "."
(string-take commit 7))))
(sha256
(base32
"1h5lppqqxcvdg5jq42i5msgwx20ryij3apvmndflngrgdpc04gn1")))))
("farmhash-src"
,(let ((commit "816a4ae622e964763ca0862d9dbd19324a1eaf45"))
(origin
(method url-fetch)
(uri (string-append
"https://mirror.bazel.build/github.com/google/farmhash/archive/"
commit ".tar.gz"))
(file-name (string-append "farmhash-0-" (string-take commit 7)
".tar.gz"))
(sha256
(base32
"185b2xdxl4d4cnsnv6abg8s22gxvx8673jq2yaq85bz4cdy58q35")))))
;; The license notice on the home page at
;; http://www.kurims.kyoto-u.ac.jp/~ooura/fft.html says:
;; Copyright Takuya OOURA, 1996-2001
;;
;; You may use, copy, modify and distribute this code for any purpose
;; (include commercial use) and without fee. Please refer to this
;; package when you modify this code.
;;
;; We take the identical tarball from the Bazel mirror, because the URL
;; at the home page is not versioned and might change.
("fft2d-src"
,(origin
(method url-fetch)
(uri "https://mirror.bazel.build/www.kurims.kyoto-u.ac.jp/~ooura/fft.tgz")
(file-name "fft2d.tar.gz")
(sha256
(base32
"15jjkfvhqvl2c0753d2di8hz0pyzn598g74wqy79awdrf1y67fsj"))))
("highwayhash-src"
,(let ((commit "be5edafc2e1a455768e260ccd68ae7317b6690ee")
(revision "1"))
(origin
(method git-fetch)
(uri (git-reference
(url "https://github.com/google/highwayhash.git")
(commit commit)))
(file-name (string-append "highwayhash-0-" revision
(string-take commit 7)
"-checkout"))
(sha256
(base32
"154jwf98cyy54hldr94pgjn85zynly3abpnc1avmb8a18lzwjyb6")))))
("nsync-src"
,(let ((version "0559ce013feac8db639ee1bf776aca0325d28777")
(revision "1"))
(origin
(method url-fetch)
(uri (string-append "https://mirror.bazel.build/"
"github.com/google/nsync/archive/"
version ".tar.gz"))
(file-name (string-append "nsync-0." revision
"-" (string-take version 7)
".tar.gz"))
(sha256
(base32
"0qdkyqym34x739mmzv97ah5r7ph462v5xkxqxvidmcfqbi64b132")))))
("re2-src"
,(let ((commit "e7efc48")
(revision "1"))
(origin
(method git-fetch)
(uri (git-reference
(url "https://github.com/google/re2")
(commit commit)))
(file-name (string-append "re2-0-" revision
(string-take commit 7)
"-checkout"))
(sha256
(base32
"161g9841rjfsy5pn52fcis0s9hdr7rxvb06pad38j5rppfihvign")))))
("googletest" ,googletest)
("swig" ,swig)
("unzip" ,unzip)))
(propagated-inputs
`(("python-absl-py" ,python-absl-py)
("python-astor" ,python-astor)
("python-gast" ,python-gast)
("python-grpcio" ,python-grpcio)
("python-numpy" ,python-numpy)
("python-protobuf" ,python-protobuf-next)
("python-six" ,python-six)
("python-termcolo" ,python-termcolor)
("python-wheel" ,python-wheel)))
(inputs
`(("c-ares" ,c-ares-next)
("eigen" ,eigen-for-tensorflow)
("gemmlowp" ,gemmlowp-for-tensorflow)
("lmdb" ,lmdb)
("libjpeg" ,libjpeg)
("libpng" ,libpng)
("giflib" ,giflib)
("grpc" ,grpc)
("jsoncpp" ,jsoncpp-for-tensorflow)
("snappy" ,snappy)
("sqlite" ,sqlite)
("protobuf" ,protobuf-next)
("python" ,python-wrapper)
("zlib" ,zlib)))
(home-page "https://tensorflow.org")
(synopsis "Machine learning framework")
(description
"TensorFlow is a flexible platform for building and training machine
learning models. It provides a library for high performance numerical
computation and includes high level Python APIs, including both a sequential
API for beginners that allows users to build models quickly by plugging
together building blocks and a subclassing API with an imperative style for
advanced research.")
(license license:asl2.0)))