Theano Python教程

时间:2020-02-23 14:43:45  来源:igfitidea点击:

Theano是Python的数值计算库。
这是实现神经网络模型的常见选择,因为它使您可以有效地定义,优化和评估数学表达式,包括多维数组((numpy.ndaray))。

Theano Python

Theano使获得高速成为可能,从而在涉及大量数据的问题上与手工C实现进行了激烈的竞争。
它可以利用最新的GPU,在某些情况下,它在CPU上的性能要比C高出好几个数量级。

Theano有一个了不起的编译器,它可以进行各种复杂度不同的优化。
一些这样的优化是:

  • 算术简化(例如:--x-> x; x + y-x-> y)
  • 使用内存别名以避免计算
  • 不断折叠
  • 合并相似的子图,以避免重复计算
  • 循环融合用于元素子表达式
  • GPU计算

您可以在此处查看优化的完整列表。

为什么选择Theano Python库?

通常,我们使用numpy软件包来处理矩阵,那么什么使Theano优于任何此类软件包!

Theano是numpy和sympy之间的一种混合体,它试图将两者组合成一个功能强大的库。
让我们来看看它相对于其他的一些优势:

  • 稳定性优化:Theano可以找出一些不稳定的表达式,并可以使用更稳定的方式对其进行评估
  • 执行速度优化:如前所述,theano可以利用最新的GPU并在您的CPU或者GPU中执行部分表达式,从而使其比Python快得多
  • 符号区分:Theano足够聪明,可以自动创建符号图以计算梯度

好了,从理论上讲,让我们开始研究示例部分。

Theano教程

要开始使用Theano,请使用PIP进行安装,如下图所示。

Theano表达式到可调用对象中

使用Theano,我们可以将表达式转换为可调用对象。
让我们看一下代码片段:

import theano
from theano import tensor

x = tensor.dscalar()
y = tensor.dscalar()

z = x + y
f = theano.function([x,y], z)
print(f(1.5, 2.5))

运行此命令时,将得到以下输出:现在,让我们尝试了解上述程序中发生的情况:

  • 我们首先声明两个符号浮点标量或者变量
  • 然后,我们创建了一个简单的表达式,将两个数字相加
  • 在表达式之后,我们将表达式转换为可调用对象,该对象以(x,y)作为输入,并在计算后返回z的值
  • 最后,我们使用一些参数调用该函数并打印结果

物流功能

让我们看一个更复杂的示例,而不只是将两个数字相加。
让我们尝试计算logistic曲线,它由下式给出:如果为该方程式绘制图形,将看起来像:Logistic函数应用于矩阵的每个元素。
让我们写一个代码片段来演示这一点:

import theano
from theano import tensor

# declare a variable
x = tensor.dmatrix('x')

# create the expression
s = 1/(1 + tensor.exp(-x))

# convert the expression into a callable object which takes
# a matrix as parameter and returns s(x)
logistic = theano.function([x], s)

# call the function with a test matrix and print the result
print(logistic([[0, 1], [-1, -2]]))

运行脚本时,我们可以看到输出:一切正常,输出看起来与预期的相同。
现在,让我们仔细看看这些功能。

仔细看看Theano函数

Theano函数有助于与符号图进行交互。
它们允许theano构建计算图并对其进行优化。

典型的theano函数如下所示:

f= theano.function([x],y)

x是输入变量的列表,y是输出变量的列表。
我们来看看此功能的用处。

一次计算多个结果

假设我们必须计算两个矩阵" x"和" y"之间的元素差,绝对差和平方差。
同时执行此操作可以极大地优化程序,因为我们不必为每个操作而一次又一次地转到每个元素。

import theano
from theano import tensor

# declare variables
x, y = tensor.dmatrices('x', 'y')

# create simple expression for each operation
diff = x - y

abs_diff = abs(diff)
diff_squared = diff**2

# convert the expression into callable object
f = theano.function([x, y], [diff, abs_diff, diff_squared])

# call the function and store the result in a variable
result= f([[1, 1], [1, 1]], [[0, 1], [2, 3]])

# format print for readability
print('Difference: ')
print(result[0])

print('Absolute Difference: ')
print(result[1])

print('Squared Difference: ')
print(result[2])

运行此程序时,我们可以看到输出为多个打印结果:

使用Theano渐变功能

让我们尝试一些更有用和更复杂的功能,以逐步简化培训示例。
其中我们将尝试找出表达式相对于参数的导数

我们将计算上面定义的逻辑函数的梯度,可以将其绘制为:让我们通过一个示例演示Gradient的工作方式:

import numpy
import theano
from theano import tensor
from theano import pp

# declare variable
x = tensor.dmatrix('x')

#create a simple expression for logistic function
s = tensor.sum(1/(1 + tensor.exp(-x)))

# create expression to compute gradient of s with respect to x
gs = tensor.grad(s, x)

# create callable object
dlogistic = theano.function([x], gs)

# call the function and print the results
print(dlogistic([[0, 1], [-1, -2]]))

当我们运行该程序时,我们可以看到输出为:这样,即使对于具有许多输入的函数,Theano也可用于进行有效的符号微分(因为tensor.grad返回的表达式将在编译过程中进行优化)。

让我们将它们放到一个简单的培训示例中,以更好地了解theano!

最少培训Theano示例

让我们尝试使用theano训练一些东西。
我们将使用梯度下降来训练W中的权重,以便从模型中获得比现有(0.9)更好的结果:

import theano
import numpy

# declare variables
x = theano.tensor.fvector('x')
target = theano.tensor.fscalar('target')
W = theano.shared(numpy.asarray([0.2, 0.7]), 'W')

# create expressions
y = (x * W).sum()
cost = theano.tensor.sqr(target - y)
gradients = theano.tensor.grad(cost, [W])

W_updated = W - (0.1 * gradients[0])
updates = [(W, W_updated)]

# create a callable object from expression
f = theano.function([x, target], y, updates=updates)

# call the function and print results
for i in range(10):
  result = f([1.0, 1.0], 20.0)
  print(result)

运行此程序时,我们可以看到以下输出:第二个输入变量" target"将用作我们用于训练的目标值:

target = theano.tensor.fscalar('target')

我们需要一个成本函数来训练模型,通常是与目标值的平方距离

cost = theano.tensor.sqr(target - y)

接下来,我们需要为要相对于成本函数更新的参数计算局部梯度。
正如我们在较早的示例中看到的那样,Theano将为我们做到这一点。
我们只需使用必需的参数调用grad函数即可:

gradients = theano.tensor.grad(cost, [W])

现在,为参数的更新版本定义一个变量。
众所周知,在梯度下降中,更新值等于学习率乘以从现有值中减去的梯度。

假设学习率α= 0.1:

W_updated = W - (0.1 * gradients[0])

接下来,我们必须再次定义Theano函数,进行一些更改:

f = theano.function([x, target], y, updates=updates)

调用该函数时,它将获取x和target的值,并返回y的值作为输出,然后Theano执行更新列表中的所有更新。

现在我们反复调用该函数以进行训练,在此示例中要重复10次以具体说明。
通常,训练数据包含不同的值,但出于本示例的目的,我们每次使用相同的值x = [1.0,1.0]和target = 20来检查事情是否正常运行。

在上面的输出中,请注意目标值在每个步骤中如何接近20(目标值)。