theano ile döngüler

Temel tarama kullanımı

‘scan’, bir değerler listesi üzerinden işlevi birden çok kez çağırmak için kullanılır, işlev durum içerebilir.

“tarama” sözdizimi (theano 0.9’dan itibaren):

scan(
    fn,
    sequences=None,
    outputs_info=None,
    non_sequences=None,
    n_steps=None,
    truncate_gradient=-1,
    go_backwards=False,
    mode=None,
    name=None,
    profile=False,
    allow_gc=None,
    strict=False)

Bu ilk bakışta çok kafa karıştırıcı olabilir. Birden çok kod örneğinde birkaç temel ancak önemli “tarama” kullanımını açıklayacağız.

Aşağıdaki kod örnekleri, içe aktarma işlemini gerçekleştirdiğinizi varsayar:

import numpy as np
import theano
import theano.tensor as T

diziler - Bir işlevi bir liste üzerinde eşleyin

En basit durumda, tarama yalnızca saf bir işlevi (durumsuz bir işlev) bir listeye eşler. Listeler “sıralar” bağımsız değişkeninde belirtilir

  s_x = T.ivector()
  s_y, _ = theano.scan(
      fn = lambda x:x*x,
      sequences = [s_x])
  fn = theano.function([s_x], s_y)
  fn([1,2,3,4,5]) #[1,4,9,16,25]

Not ’tarama’nın iki dönüş değeri vardır, birincisi sonuç listesidir ve ikincisi daha sonra açıklanacak olan durum değerindeki güncellemelerdir.

sequences - Bir işlevi bir liste üzerine sıkıştırın

Hemen hemen yukarıdakiyle aynı, sadece “diziler” argümanına iki öğeden oluşan bir liste verin. İki öğenin sırası, ‘fn’ içindeki bağımsız değişkenlerin sırasına uymalıdır.

  s_x1 = T.ivector()
  s_x2 = T.ivector()
  s_y, _ = theano.scan(
      fn = lambda x1,x2:x1**x2,
      sequences = [s_x1, s_x2])
  fn = theano.function([s_x], s_y)
  fn([1,2,3,4,5],[0,1,2,3,4]) #[1,2,9,64,625]

outputs_info - Bir liste biriktirin

Biriktirme bir durum değişkeni içerir. Durum değişkenleri, “outputs_info” parametresinde belirtilecek olan başlangıç ​​değerlerine ihtiyaç duyar.

  s_x = T.ivector()
  v_sum = th.shared(np.int32(0))
  s_y, update_sum = theano.scan(
      lambda x,y:x+y,
      sequences = [s_x],
      outputs_info = [s_sum])
  fn = theano.function([s_x], s_y, updates=update_sum)
  
  v_sum.get_value() # 0
  fn([1,2,3,4,5]) # [1,3,6,10,15]
  v_sum.get_value() # 15
  fn([-1,-2,-3,-4,-5]) # [14,12,9,5,0]
  v_sum.get_value() # 0

‘outputs_info’ya paylaşılan bir değişken koyarız, bu, paylaşılan değişkenimize ’tarama’ dönüş güncellemelerine neden olur, bu da daha sonra ’theano.function’ içine konabilir.

non_sequences ve n_steps - Lojistik haritasının yörüngesi x -> lambda*x*(1-x)

’non_sequences’ argümanında ’tarama’ sırasında değişmeyen girdiler verebilirsiniz. Bu durumda ’s_lambda’ değişmeyen bir değişkendir (ancak çalışma zamanı sırasında sağlanması gerektiğinden bir sabit DEĞİLDİR).

  s_x = T.fscalar()
  s_lambda = T.fscalar()
  s_t = T.iscalar()
  s_y, _ = theano.scan(
      fn = lambda x,l: l*x*(1-x),
      outputs_info = [s_x],
      non_sequences = [s_lambda],
      n_steps = s_t
  )
  fn = theano.function([s_x, s_lambda, s_t], s_y)

  fn(.75, 4., 10) #a stable orbit

  #[ 0.75,  0.75,  0.75,  0.75,  0.75,  0.75,  0.75,  0.75,  0.75,  0.75]

  fn(.65, 4., 10) #a chaotic orbit

  #[ 0.91000003,  0.32759991,  0.88111287,  0.41901192,  0.97376364,
  # 0.10219204,  0.3669953 ,  0.92923898,  0.2630156 ,  0.77535355]

Musluklar - Fibonacci

durumlar/girişler birden çok zaman adımında gelebilir. Bu şu şekilde yapılır:

  • ‘diziler’ argümanının içine ‘dict(input=<init_value>, taps=)’ koyma.

  • ‘outputs_info’ argümanının içine ‘dict(initial=<init_value>, taps=)’ ifadesini koymak.

Bu örnekte, “x_n = x_{n-1} + x_{n-2}” yineleme ilişkisini hesaplamak için “outputs_info"da iki dokunuş kullanıyoruz.

s_x0 = T.iscalar()
s_x1 = T.iscalar()
s_n = T.iscalar()
s_y, _ = theano.scan(
    fn = lambda x1,x2: x1+x2,
    outputs_info = [dict(initial=T.join(0,[s_x0, s_x1]), taps=[-2,-1])],
    n_steps = s_n
)
fn_fib = theano.function([s_x0, s_x1, s_n], s_y)
fn_fib(1,1,10)
# [2, 3, 5, 8, 13, 21, 34, 55, 89, 144]

theo haritası ve azaltın

“theano.map” ve “theano.scan_module.reduce”, “theano_scan” sarmalayıcılarıdır. “Scan”ın engelli versiyonu olarak görülebilirler. Referans için Temel tarama kullanımı bölümünü inceleyebilirsiniz.

import theano
import theano.tensor as T
s_x = T.ivector()
s_sqr, _ = theano.map(
    fn = lambda x:x*x,
    sequences = [s_x])
s_sum, _ = theano.reduce(
    fn = lambda: x,y:x+y,
    sequences = [s_x],
    outputs_info = [0])
fn = theano.function([s_x], [s_sqr, s_sum])
fn([1,2,3,4,5]) #[1,4,9,16,25], 15

while döngüsü yapmak

theano 0.9’dan itibaren while döngüleri theano.scan_module.scan_utils.until üzerinden yapılabilir. Kullanmak için, ’tarama’nın ‘fn’sindeki ‘until’ nesnesini döndürmelisiniz.

Aşağıdaki örnekte, karmaşık bir sayının Mandelbrot kümesinin içinde olup olmadığını kontrol eden bir fonksiyon oluşturuyoruz. “z_{n+1} = z_{n}^2 + z_0” serisi yakınsamazsa, “z_0” karmaşık sayısı mandelbrot kümesinin içindedir.

MAX_ITER = 256
BAILOUT = 2.
s_z0 = th.cscalar()
def iterate(s_i_, s_z_, s_z0_):
    return [s_z_*s_z_+s_z0_,s_i_+1], {}, until(T.abs_(s_z_)>BAILOUT)
(_1, s_niter), _2 = theano.scan(
    fn = iterate,
    outputs_info = [0, s_z0],
    non_sequences = [s_z0],
    n_steps = MAX_ITER
)
fn_mandelbrot_iters = theano.function([s_z0], s_niter)
def is_in_mandelbrot(z_):
    return fn_mandelbrot_iters(z_)>=MAX_ITER

is_in_mandelbrot(0.24+0.j) # True
is_in_mandelbrot(1.j) # True
is_in_mandelbrot(0.26+0.j) # False