深度学习中的函数语言之美 - Clojure和Haskell


深度学习是基于人工神经网络的机器学习方法的子集。这些都受到大脑等生物系统中的信息处理和分布式通信节点的启发。在深度学习中,每个级别都学习将输入数据转换为稍微更抽象和复合的表示。例如,在面部识别系统中,像素可能是系统的一层,而边缘可能是另一层,眼睛可能是另一层,而脸可能是另一层。深度学习方法的复杂性使得使用编程社区中流行的现有包TensorFlowPyTorch,由此 Python很受欢迎,然而,在生产深度学习系统,性能和安全性是推动公司选择Clojure和Haskell等函数式编程语言的两个问题。

深度学习实施的困难
在将深度学习系统投入生产时,神经网络可能包含一百万个参数。数据可以快速爆炸以训练这些参数。这种数据爆炸需要的性能只能通过具有安全并发和并行功能的高效编程语言来实现。由于神经网络的复杂性,数据从一层传递到另一层,编程语言处理这些数据的方式的简单性和一致性非常重要。在这种情况下,安全性意味着能够以一致的方式保留原始数据的状态,而简单性意味着能够在最大化性能的同时轻松读取和维护代码库。

为什么函数式编程更适合深度学习
为了解决实现深度学习时可能遇到的一些困难,程序员发现函数式编程语言可以提供解决方案。
在计算机科学中,函数式编程是一种编程范式,它将计算视为数学函数的评估,并避免改变状态和可变数据。这是一种更接近数学思维的编程模式。
深度学习模型本质上是数学模型。例如,人工神经网络包括连接的节点,每个节点执行简单的数学运算。通过使用函数式编程语言,程序员能够以更接近操作本身的语言描述这些数学运算。这些程序的显式编写方式使得阅读和维护代码库变得更加容易。
同时,深度学习算法的组成性质意味着,在神经工作的每一层,层或功能倾向于链接在一起以执行任务。这可以使用函数编程语言的功能链来容易地实现。
此外,在深度学习中,当函数应用于数据时,数据不会改变。可以按行顺序输出新值,但数据本身保持一致。函数式编程语言的不变性特性将允许程序员在每次生成新值时创建新数据集而不改变原始不可变数据集。这使得更容易在整个神经网络中保持数据的一致性。
最后,深度学习实现中涉及的大量参数和训练数据意味着并行性和并发性是创建生产级深度学习系统的关键。并行性意味着在不同的CPU上运行线程以加速学习过程。并发意味着管理线程以避免冲突的能力。函数式编程允许免费并发和并行。这意味着,就其性质而言,纯函数是无状态的函数式编程将始终为特定输入生成相同的输出,从而能够隔离任何函数,并在需要时执行。这使得并发和并行更容易管理。您不必处理死锁和竞争条件等问题。访问不同CPU的不同线程将能够独立运行而不会出现争用。

Clojure
随着函数性编程在深度学习中的普及,以及可用于深度学习的强大软件包,Clojure现在受到沃尔玛和Facebook等公司的青睐。它是一种基于LISP编程语言的高级动态函数式编程语言,它具有可以在Java和.NET运行时环境中运行的编译器。
Clojure不会取代Java线程系统,而是使用它。由于核心数据结构是不可变的,因此可以在线程之间轻松共享它们。同时,程序中的状态变化是可能的,但Clojure提供了确保状态保持一致的机制。如果尝试修改同一引用的2个事务之间发生冲突,则其中一个将退出。不需要显式锁定。

(import ‘(java.util.concurrent Executors))
(defn test-stm [nitems nthreads niters]
 (let [refs (map ref (repeat nitems 0))
   pool (Executors/newFixedThreadPool nthreads)
   tasks (map (fn [t]
               (fn []
                (dotimes [n niters]
                  (dosync
                   (doseq [r refs]
                    (alter r + 1 t))))))
              (range nthreads))]
   (doseq [future (.invokeAll pool tasks)]
      (.get future))
   (.shutdown pool)
   (map deref refs)))
(test-stm 10 10 10000) -> (550000 550000 550000 550000 550000 550000 550000 550000 550000 550000)

Clojure中的并行性很便宜
在深度学习中,模型必须训练大量数据。并行性意味着在不同的CPU上运行多个线程。便宜的并行性意味着显着的性能改进。将分区与map结合使用可以实现成本更低的并行性。

(defn calculate-pixels-2 []
 (let [n (* *width* *height*)
       work (partition (/ n 16) (range 0 n))
       result (pmap (fn [x]
                  (doall (map
                   (fn [p]
                     (let [row (rem p *width*) col (int (/ p *height*))]
                       (get-color (process-pixel (/ row (double *width*)) (/ col (double *height*))))))
                   x)))
                  work)]
   (doall (apply concat result))))

Clojure中的链接函数意味着清晰
在Clojure中,很少有数据类型的函数。函数也可以作为参数传递给其他函数,这使得深度学习中的链接函数成为可能。通过更接近实际数学模型的实现,Clojure代码可以易于阅读和维护。

;; pipe arg to function
(-> "x" f1) ; "x1"

;; pipe. function chaining
(->
"x" f1 f2) ; "x12"

Clojure中的标识身份和状态提供了安全性
在Clojure中,每个模型的标识身份在任何时间点都有一个状态。这种状态是永远不变的真正值。如果身份似乎发生变化,这是因为它与不同的状态相关联。新的值是旧的函数。在神经网络的每一层内,始终保留原始数据的状态。具有作为函数输出的新值的每组数据可以独立操作。这意味着可以安全地对这些数据集执行操作,也可以不考虑争用。我们可以随时参考数据的原始状态。因此,在这种情况下,一致性意味着安全。
随着最近用于深度学习的开源MXNet框架的日益普及,使用MXNet-Clojure API实现深度学习更容易。
虽然现在有不同的API和机器学习库可用于Clojure,但仍然有一个陡峭的学习曲线,以便流利。错误消息可能含糊不清,公司需要愿意提前投资以使用它来扩展其机器学习系统。随着更多生产就绪系统的例子都是用Clojure编写的,这种语言在未来几年会越来越受欢迎,但前提是随着Clojure的使用而增加的库的数量和大小也会增加。

Haskell
Haskell是一种函数式语言,通过类型推断和惰性求值进行静态类型化。它基于Miranda编程语言的语义,被认为更加富有表现力,更快,更安全,可用于实现机器学习。
1.Haskell中的类型安全性提供了安全性和灵活性
类型安全性定义了变量可以容纳的值类型的约束。这将有助于防止非法操作,提供更好的内存安全性,并减少逻辑错误。延迟评估意味着Haskell将延迟表达式的求值,直到需要它的值。它还避免了重复评估,这将节省运行时间。同时,延迟评估允许定义无限数据结构。这为程序员提供了无限的数学可能性。
2.Haskell中的简单显式代码提供了清晰的实现
Haskell的最大好处之一是它可以用非常明确的数学结构来描述算法。您可以在几行代码中表示模型。您也可以像读取数学方程一样阅读代码。这在复杂算法中非常强大,例如机器学习中的深度学习算法。例如,前馈神经网络的单层的以下实现显示了代码的可读性。

import Numeric.LinearAlgebra.Static.Backprop
logistic :: Floating a => a -> a
logistic x = 1 / (1 + exp (-x))
feedForwardLog
   :: (KnownNat i, KnownNat o)
   => Model (L o i :& R o) (R i) (R o)
feedForwardLog (w :&& b) x = logistic (w #> x + b)

3.Haskell中的多核并行性提供了性能
在深度学习中,典型的神经网络将包含定义模型的一百万个参数。此外,需要大量数据来学习这些参数,这在计算上非常耗时。在一台机器上,使用多个内核并行共享内存和进程在实现深度学习时非常强大。但是,在Haskell中,实现多核并行性很容易。
Haskell的HLearn库包含机器学习算法实现,而Haskell 的张量流绑定可用于深度学习。同时,Parallel和Concurrent用于并行和并发。
虽然在Haskell中开发了一些机器学习库,但仍需要为生产就绪的Haskell实现进行全面实现。虽然可用于特定深度学习和机器学习任务的公共库有限,但Haskell在AI中的使用也将受到限制。像Aetion Technologies和瑞士信贷全球建模与分析集团这样的公司正在他们的实施中使用Haskell- 这里是使用它的组织的完整列表

结论
深度学习模型是复杂的数学模型,需要特定的功能分层。诸如Clojure和Haskell之类的函数式编程语言通常可以用更接近模型数学的更清晰的代码来表示复杂性。这样可以节省时间,提高效率并轻松管理代码库。函数式编程的特定属性允许这些语言中的实现比其他语言更安全。随着人工智能技术的发展,人工智能中大规模系统开发项目的需求评估这些语言将变得更加普遍。