Tensorflow'u Anlamak

Bu yazıda bahsedilen konular;

  • Tensorflow nedir?
  • Tensorflow birimleri nelerdir, nasıl çalışır?

Not: Yazın içerisinde bilumum yabancı kelimeler, devşirilmiş kelimeler bulunmaktadır; implement etmek, multilayer, deep learning, graph vb. Maalesef, çeviri bir takım kavramlara aşina değilim. Tek tek, her kavramın Türkçe karşılığına bakmak, oldukça yavaşlatıyor. Kaldı ki, kavramların orjinalini kullanmak ve öğrenmek bana, daha uygun gibi geliyor. Diğer taraftan okunurluk azalıyor. Tabii ki tartışılır bir konu, bu benim kişisel tercihim…

Bu yazıda Tensorflowun kurulumundan bahsetmedim. Başlamadan önce kurmanız iyi olacaktır. Yazının temel amacı Tensorflow yapısını anlamaktır. Bu yüzden biraz sıkıcı olabilir ama genel olarak bir Tensorflow programı görünce ne yaptığını anlayabilecek düzeye gelinebileceğine inanıyorum.

Tensorflow

Tensorflow’un gerçekten çok aşığı var ve bu ilgi bölgesel veya dönemsel bir ilgi değil. Şuradaki konferansta Martin Gorner ilgiden etkilendiğini belirtiyor, görüldüğü gibi gerçekten ilgi büyük ve teknoloji bu ilgiyi hakediyor. Bir yazılım geliştiricisinin Tensorflow ile birlikte bir kaç saatte deep learninge aşina durumuna geleceği söylenir. Bu durum aslında SŞA(San Francisco şartları altında) mümkün gibi görünüyor. NŞA(Normal şartlar altında) bir geliştiricinin bir kaç saatte kavraması zordur zannmıca. tensorflow tokat Komik degil..

Tensorflow Google’ın geliştirdiği açık kaynak bir deep learning frameworküdür. Ancak yaygın olarak deep learning uygulamalarında kullanılsa da Tensorflow daha geniş bir alanı kapsar: “Computational Graphs”.

Tensorflow’un kendi sitesindeki tanımı şöyle:

TensorFlow™ is an open source software library for numerical computation using data flow graphs. Nodes in the graph represent mathematical operations, while the graph edges represent the multidimensional data arrays (tensors) communicated between them. The flexible architecture allows you to deploy computation to one or more CPUs or GPUs in a desktop, server, or mobile device with a single API.

Tensorflow, data flow graphları kullanarak numerik hesaplama için geliştirilmiş açık kaynak bir kütüphanedir. Graphlardaki nodelar matematiksel işlemleri(operation) temsil eder, graph edgeleri(kenarları) birbirleri arasında iletilen çok boyutlu arrayleri(tensor) temsil eder. Esnek yapısı sayesinde, tek bir API ile platform farketmeksizin hesaplamaları, bir veya birden fazla CPU, GPU kullanarak deploy etmenize olanak sağlar.

Graphlar hakkında bir fikir edinmek isterseniz; Türkçe, İngilizce.

Ana fikir: Numerik hesaplamaları graph şeklinde ifade etmek.

  • Graph nodeları, herhangi bir sayıda inputa ve outputa sahip işlemleri ifade eder.
  • Graph edgeleri, nodelar arası akışı sağlayan tensorlardır.

Temel olarak Tensorflow N dimensional arrayler ile graph işlemlerinin otomatik olarak yapılabildiği bir kütüphanedir.

numpy ile karşılaştıracak olursak numpy n dimansional array kütüphanesidir ancak Tensorflow gibi, tensor fonksiyonları oluşturacak ve numerik hesaplamaları otomatik olarak yapacak bir yapısı yoktur.

Şurada güzel bir kaşılaştırma mevcut. alt text

Görüldüğü gibi array operasyonları birbirlerine çok benziyor. Zaten bir Tensorflow programı yazarken sıkı bir şekilde NumPy’dan da faydalanılmaktadır. Tensorflow programı ifadesini kullanıyorum çünkü Tensorflow kendi dökümantasyonlarında bu ifadeyi sıkça kullanıyor. Tenorflow’un ileride değineceğimiz session yapısı C++ ile yazılmıştır. Python ve diğer bir takım dillerde kullanılan fonksiyonlar C++ backendinde yazılmış fonksiyonları kullanmaktadır.

Aslında Tensorflow deep learning uygulamarı için düşük seviyede bir API sunuyor. Keras veya Tensorflowun kendi içerisinde bulunan tf.estimator.Estimator gibi API’lar session yapısını saklar ve hazır modeller kullanark daha hızlı geliştirme yapmak için ciddi olanak sağlar. Daha düşük seviyedeki API, daha önce geliştirilmemiş bir model geliştirmek için veya mevcut modelleri probleme uygun bir şekilde değiştirmek için kullanılır.

Küçük Bir Örnek

Hızlı bir başlangıç için bir çok rehberde mevcut olan küçük bir örneği yapalım. Daha sonra bu yapıları biraz daha ayrıntılı bir şekilde inceleyeceğiz. Çok sıkça kullanılan bir ReLU modelinin temelini programlıyacağız.

Öncelikle bir ReLU modelinin matematiksel ifadesi şu şekilde:

h = ReLU(Wx + b)

BUradaki ifadeyi deep learning ile aşina olanlar daha önce görmüşlerdir.

Böyle bir matematiksel ifade computational graph olarak figurdekiReLU
ReLU Computational Graph

gibi gorunur.

Şekiller anlamak için gerçekten de çok faydalı materyaller. Şekilde görmüş olduğumuz mavi yuvarlak node (b, w) değişkenlerdir (Variables). Variablelar state durumuna göre output olarak o andaki değerini iletir. State birden fazla defa çalıştırılan graphlarda ortaya çıkar. Variablelar çoğunlukla parametreler için kullanılır. (Deep learning parameters)

Turkuaz renkte olan yuvarlak node (X) bir placeholderdır. Placeholderlar değerleri execution timeda beslenen (feed) nodelardır. Bu nodelar inputlar ve labelların her bir adımda feed edilmesi (besleme) için kullanılır.

Diğer nodelar matematiksel operationları temsil ediyor.

  • MatMul: Matris çarpımı
  • Add: Toplama
  • ReLU: Rectified Linier Function (Basit bir aktivasyon fonksiyonu)

Evet bu kadar tatava yeter şimdi koda bakalım:

import tensorflow as tf

# değişkenleri tanımlıyoruz
b = tf.Variable(tf.zeros((100,))) # 100x1 boyutunda 0'larla dolu bir vektör 
                                  # burada listenin sonuna konan virgül çok garip duruyor
                                  # bazen de kafa karıştırabiliyor
                                  # bu virgül sayesinde tek elemanı olan bir tuple parametre olarak vermiş oluyoruz
                                  # sadece 100 yazmış olsaydık integer olurdu

W = tf.Variable(tf.random_uniform((784, 100), -1, 1))  # 784x100 boyutlarında [-1, 1) aralığında 
                                                       # float random sayılardan oluşan bir vektör

# placeholder tanımılıyoruz
x = tf.placeholder(tf.float32, (100, 784)) # placeholder execution timeda feed edilecek

# ve son olarak graph
h = tf.nn.relu(tf.matmul(x, W) + b)

Böylece graphı oluşturduk. Buradaki h değişkeni artık bir graph. Tensorflowda bulunan session yapısı ile artık garphı çalıştırabiliriz. Session tercihe bağlı olarak GPU veya CPU kullanarak çalışabilir.

import numpy as np
import tensorflow as tf

b = tf.Variable(tf.zeros((100,)))
W = tf.Variable(tf.random_uniform((784, 100), -1, 1))
x = tf.placeholder(tf.float32, (100, 784))

h = tf.nn.relu(tf.matmul(x, W) + b)

# session oluşturuyoruz
sess = tf.Session()

# session ilk defa oluşturulduktan sonra initialize edilmeli
sess.run(tf.initialize_all_variables())

# sessionnı çalıştırıyoruz
sess.run(h, {x: np.random.random(100, 784)}) # burada input olarak oluşturduğumuz graph(h)
                                             # ve x placeholderı için feed input olarak veriyoruz
sess.run(fetches, feeds)

Fetches: Graph nodeları listesi. Session bu nodeların sonuçlarını return eder. Feeds: Graphda bulunan nodeların bir dictionarysidir. İstenilen nodeun değeri verilir. Placeholderların feed olayı bu şekilde gerçekleştirilir.

Tensorflow yapısını kafada şekillenmesi adına küçük bir örnek işledik. Şimdi tensorflow birimlerinin biraz daha ayrıntılarına girelim.

Tensor

Tensorlar adından da anlaşıldığı gibi Tensorflow’un temelini oluşturan birimdir. Tensorlar belirli bir datatypeı baz alan n dimensional arraylerdir.

Kafamızda canlanması adına küçük bir kaç örneğe hızlıca bakalım:

# bu bir tensor
s = tf.Variable("Napoleon", tf.string)

# aynı şekilde bu da
a = tf.Variable([2.0, 3.2, 5.5], tf.float32)

Örnekten de anlaşılacağı gibi tf.Tensor’ların iki özelliği vardır: - datatype (string, float32, int32 vs.) - shape (şekli, [1], [1, 2, 1] vs.)

Dökümantasyonda şöyle güzel bir açıklama mevcut:

When writing a TensorFlow program, the main object you manipulate and pass around is the tf.Tensor. A tf.Tensor object represents a partially defined computation that will eventually produce a value. TensorFlow programs work by first building a graph of tf.Tensor objects, detailing how each tensor is computed based on the other available tensors and then by running parts of this graph to achieve the desired results.

Kabaca diyor ki tf.Tensor, Tensorflow programlarının ana nesnesidir. Tensorflow programları tf.Tensor nesnelerinden oluşan bir graph oluşturularak başlar. Daha sonra her tensorın diğer tensorlere bağlı olarak nasıl hesaplanacağı tanımlanır ve sonuçları elde etmek üzere graph çalıştırılır. Tensorflow ile bir model geliştirilirken genel olarak bu adımlar takip edilir.

Tensor nesnelerinin elementleri aynı datatypelardır ve datatype her zaman bilinir. Ancak shapeler her zaman bilinemeyebilir. Kimi zaman anlaşılabilirken, kimi zaman shape, graph execution anında (execution time) bilinmesi mümkün olur. Bazı özel Tensor tipleri mevcut bunlara daha sonra kullancağız. Şunlar en sık kullanılanlar: tf.Variable, tf.Constant, tf.Placeholder.

Rank

Rank çok basit bir ifadeyle tf.Tensorın boyutunu ifade eder.

Rank Matematik Karşılığı
0 Skaler
1 Vektör
2 Matris
3 3-Tensor
n n-Tensor

Bir kaç küçük örnek:

# Rank 0
s = tf.Variable("G.O.R.A", tf.string)
i = tf.Variable(0, tf.int32)
_complex = tf.Variable((1.1, -2.2), tf.complex64)

# Rank 1
arr_s = tf.Variable(["Fire", "Water", "Earth", "Tahta"], tf.string)
arr_i = tf.Variable([1071, 1453, 1923], tf.int32)

# Rank n
_xor = tf.Variable([[False, True],[True, False]], tf.bool)
linear_squares = tf.Variable([[4], [9], [16], [25]], tf.int32)

# image temsilen örnek bir tensor
img = tf.zeros([10, 299, 299, 3])  # batch x height x width x color

Shape

Bir Tensorın shapei her boyuttaki element sayısını gösterir. Rankda olduğu gibi shape Tensorın yapısına göre oluşturulduğu anda veya execution timeda bilinir.

Aşağıdaki tablo gayet açıklayıcı:

Rank Shape
0 []
1 [D0]
2 [D0, D1]
4 [D0, D1, D2, D3]

Bir tensor nesnesinin shapeine erişmenin iki yolu mevcut:

# Shape'i bilinen tensor
tensor = tf.Variable([[1], [2]], tf.int32)
s = tensor.shape # bu bize TensorShape nesnesi döndürecektir
                 # TensorShape([Dimension(2), Dimension(1)])

# Runtime'da shape
#
# Örneğin bir matrisin kolon sayısı kadar 0'lardan
# oluşan bir vektör tanımlamak istersek
zeros = tf.zeros(tf.shape(matris)[1])

Bir de tensorların shapeini değiştirmek olayı var. Bu olay sıkça kullanılıyor ve aslında oldukça kolay. Bu konu tensorların anlaşılması açısından gerçekten çok önemli.

rank_three_tensor = tf.ones([3, 4, 5])  # Şimdi burada 3x4x5 boyutunda bir tensor oluşturduk 

matrix = tf.reshape(rank_three_tensor, [6, 10])  # Şimdi aynı içerikte 
                                                 # 6x10 boyutlarında bir tensor oluşturmuş olduk

matrix = tf.reshape(rank_three_tensor, [6, 11])  # hatalı
                                                 # Bu şekilde yapmaya çalışsaydık hata alacaktık 
                                                 # Çünkü 3x4x5 = 60 boyutundaki bir tensorı
                                                 # 6x11 = 66 boyutlarına çeviremeyiz
                                                 # reshape yapılırken boyutlara dikkat edilmeli

matrixB = tf.reshape(matrix, [3, -1])  # Aynı içerikte 3x20 boytlarında bir matris oluştur
                                       # Buradaki -1'in harika bir özelliği var
                                       # Burada boyutumuz 6x10 = 60 şeklindeydi
                                       # -1 ile o dimensionu hesaplamasını istiyoruz
                                       # Bu şekilde 3x20 = 60 boyutunda tensorumuz oluyor

matrixAlt = tf.reshape(matrixB, [4, 3, -1])  # Burada da yine aynı içerikte bir tensro oluşturuluyor
                                             # 4x3x5 boyutlarında

# Ancak tabii ki yukarıdaki hatada olduğu gibi burada da boyut aynı kalmalı
# 4x3x5'lik bir tensordan 13x2xY şeklinde bir matris oluşturulamayacaktır
yet_another = tf.reshape(matrixAlt, [13, 2, -1])  # Hatalı

Görüldüğü gibi reshape, mantığı basit ama etkili bir yöntem ve anlaşılması elzem bir kavram.

Datatype

Bildiğimiz gibi tensorların boyutun yanında bir de datatypeları mevcut. Bir tensorın farklı datatypelarda elementlere sahip olması mümkün değil. Tabii farklı tipte dataları bir string haline getirip tensor içerisinde tutabiliriz. Aykırı bir yöntem olsa da işe yarayabilir.

Programa dillerinde olduğu gibi tipler arası casting mümkün.

# int to float
float_tensor = tf.cast(tf.constant([1, 2, 3]), dtype=tf.float32)

Graphlar ve Sessionlar

Evet geldik Tensorflow’un kalbine. Tensorflow birbirlerine bağımlı operasyonların hesaplanmasını ifade etmek için dataflow graphlarını kullanır. Graphların çalıştırılması için ise bir session tanımlanır.

Tensorflow graph yapısı ve sessionlar ile düşük seviyeli bir durumda kalıyor. Keras gibi yüksek seviyede bir API sunan kütüphaneler genellikle bu session yapısını saklar.

Tensorflow’un kullandığı dataflow yapısı paralel programlama için kullanılan bilinen bir programlama modeli. Dataflow
Tensorflow Graph Dataflow

Bir dataflow graphda nodelar hesaplama unitesini temsil eder ve edgeler ise hesaplamalardan çıkan veya hesaplamalara iletilen dataları temsil eder. Dataflow yapısının bir çok avantajı mevcut; parallel programlama, distributed execution, derleme, protablitiy. Ayrıntılara şuradan gözatabilirsiniz.

Graph

Bir graph iki türden bilgi içerir;

  • Graph structure(Graph yapısı). Adından da anlaşılacağı gibi nodeların ve edgelerin bir arada nasıl bağlandıkları bilgisini içerir. Ama bu operationların nasıl kullanılacağı hakkında bilgi içermez. Tensorflow dökümantasyonunda assembly koduna benzetiliyor. Aslında herhangi bir koda benzetebiliriz. Herhangi bir programın kodu programın nasıl olduğunu tanımlar.

  • Graph collections. Bu collection yapısı Python’daki collection yapısı gibi bir yapı. tf.add_to_collection fonksiyonu nesne listelerini herhangi bir key ile saklamanızı sağlıyor. Örnek verecek olursak bir tane tf.Variable tanımladık. Bu değişken otomatik olarak global değişkenlerin collectionına eklenir. Ve bu değişkeni daha sonra collectiondan erişerek kullanabiliriz.

Graph yapısını genel olarak tanımladık. Şimdi bir tf.Graph nasıl oluşturuluyor ona bakalım. Çoğu Tensorflow programına önce graph oluşturarak başlanır. Yeni tf.Operation(node) ve tf.Tensor(edge) nesneleri oluşturulup tf.Grapha eklenir.
Sürekli bir graph yapısından bahsettik. Tensorflow bize default bir graph sunar. Ve aslında başka bir graph oluşturmamıza gerek kalmaz. Çok karmaşık yapılarda kullanılabilir ama tek bir graph genellikle graph yeterli olur. Ben dökümantasyonun yalancısıyım, şurada birden fazla graphın nasıl oluşturuacağı anlatılıyor. Arzu eden bakabilir.

Biraz da kod üzerinden gidelim.

# Tek bir satırda 11.1 üreten bir tf.Operation oluşturmuş olduk.
# Ve bunu default grapha eklemiş olduk.
# Tabii t değişkeni de constant değeri ifade eden bir tf.Tensor olmuş oldu.
t = tf.constant(11.1)

# Aynı şekilde burada da bir tf.Operation'ı oluşturup default grapha
# eklemiş olduk. Bu tf.Operation x ve y tf.Tensor nesnelerini çarpar.
# m değişkeni ise sonucu temsil eden tf.Tensor nesnesidir.
# Dikkat ederseniz temsil eden diyorum çünkü graph çalıştırılmadan 
# bu ifadeler hiçbir işe yaramıyor.
m = tf.Matmul(x, y)

Bir tf.Graph nesnesi, içerdiği tf.Operation’lar için bir namespace tanımlar. Tensorflow graphda bulunan her operation için otomatik olarak unique(eşsiz) bir isim atar. Tabii ki değişken isimlendirmelerde yaptığımız gibi mantıklı isimler vermek programımızı kolay okunabilir ve debug edilebilir yapar.

Hemen örneklere bakalım:

c_0 = tf.constant(0, name="c")  # operation adı "c"

# daha önce kullanımış isimler eşsiz yapılır (wow eşsiz yapmak).
c_1 = tf.constant(2, name="c")  # operation adı "c_1"

# Name scopelar operationlara bir prefix ekler.
# Dosya yapısı gibi düşünebilirsiniz.
with tf.name_scope("outer"):
  c_2 = tf.constant(2, name="c")  # operation adı "outer/c"

  # Doyalar gibi iç içe name scopelar oluşturulabilir
  with tf.name_scope("inner"):
    c_3 = tf.constant(3, name="c")  # operation adı "outer/inner/c"

  # Name scope dışına çıktığımızda artık o prefixi kaybederiz
  # üst klasöre çıkmak gibi.
  c_4 = tf.constant(4, name="c")  # operation adı "outer/c_1"

  # Daha önce oluşturulmuş name scopelar eşşiz yapılı.
  with tf.name_scope("inner"):
    c_5 = tf.constant(5, name="c")  # operation adı "outer/inner_1/c"

Ayrıca bu isimlendirmeler graphlar görselleştirilirken çok faydalı oluyor.

Session

Beklenen sona yaklaşıyoruz. Tensorflow graphları çalıştırmak için sessionları kullanır. Tensroflow’un kullandığı tf.Session sınıfı client program ile ( genellikle python ) C++ runtimeı arasında bağlantıyı sağlar. Aynı zamanda tf.Session nesnesi lokal cihazda yada uzaktaki bir cihazı kullanabilir. Ayrıca graphla ilgili bilgileri önbellekte tutarak aynı hesaplamaları birden çok sefer çalıştırma olanağı sağlar.

Session oluşturma;

# default bir session oluşturma
with tf.Session() as sess:
    # ...

# uzaktan bağlantılı session oluşturma
with tf.Session("grpc://example.org:2222"):
    # ..

# tf.Session nesneleri fiziksel kaynakları(GPU, network vs.) kullandığından
# kapatılması gerekir. With blockları sayesinde session otomatik olarak
# kapanır. Eğer with blocku kullanılmayacaksa session tf.Session.close
# ile kapatılmalıdır.

Session init fonksiyonu bir takım parametreler alıyor. Boş bırakılması durumunda default graph kullanılır ve cihaz olarak lokal makineyi kullanır. Ayrıntılar için dökümantasyona gözatabilirsiniz.

Session oluşturmaya baktık şimdi de sessionların nasıl çalıştığına bakalım. tf.Session.run metodu tf.Operationları çalıştırmak ve tf.Tensorları evaluate etmek için ana mekanizmadır.

tf.Session.run metodu çalıştırmak için bir fetch listesine ihtiyacı vardır. Bu fetch listesinde tf.Operation, tf.Tensor gibi nesneler olmalıdır. Parametre olarak verilen bu fetch listesi return değişkenlerini tanımlar. Fetch listesinde bulunan nesneler tf.Graphda bulunan subgraphlardan hangilerinin sonucu üreteceğini tanımlar. Bu tür tanımlamalar her zaman havada kalıyor. Bir örnekle kolayca kavranabileceğini düşünüyorum.

# graphımızı oluşturuyoruz
x = tf.constant([[37.0, -23.0], [1.0, 4.0]])
w = tf.Variable(tf.random_uniform([2, 2]))
y = tf.matmul(x, w)
output = tf.nn.softmax(y)

# initializer tanımlıyoruz
# Initializer mantığı çok basit bir mantık.
# Bir çok yerde bunun atlanıyor, belki de basit olduğundan.
# Önceden w adında bir değişken oluşturduk. Daha önceden
# belirttiğimiz gibi session çalıştırılmadan olşturduğumuz
# graphın hiçbir anlamı yok. tf.Variable'lar sabit değişkenler
# ve bu değişkenlerin graph içerisinde kullanılması için öncelikle 
# initialize edilmesi gerekiyor. Burada w değişkeni için
# bir initializer oluşturuldu.
init_op = w.initializer

with tf.Session() as sess:
  # şimdi bu initializerı sessiona verek çalıştırıyoruz.
  # böylece w değişkenimiz initialize edilmiş oldu.
  sess.run(init_op)

  # Input olarak verilen 'output' operationun sonucunu hesaplar ve
  # NumPy array şeklinde sonucu return eder.
  # Outputun hesaplanması için y tensoru da otomatik olarak hesaplanıyor.
  print(sess.run(output))

  # Burada hem y hem de output hesaplanıyor ve her ikisinin sonuçları da 
  # NumPy array olarak return ediliyor. Burada şöyle bir durum var.
  # y tensoru sadece bir kere hesaplanıyor ve sonuç hem return ediliyor
  # hem de outpu için parametre olarak kulanılıyor.
  # y_val, y operationun sonucu. ouput_val, output operationun sonucu.
  y_val, output_val = sess.run([y, output])

Ayrıca tf.Session.run parametre olarak bir feed dictionary(python dictionary) alabilir. Bu dictionary tf.Tensor nesnelerine (genellikle placeholderlar) map edilen değişkenlerden (numpy arrayler) oluşur ve çalıştırma zamanında bu nesnelerin yerlerini alır. Bu parametre genelde her stepte datanın feedlenmesi için kullanılır. Küçük bir örnek anlaşılmasına yardımcı olacak:


# 3 tane float elemandan oluşacak bir vektör bekleyen placeholder oluşturuldu.
# Dikkat ederseniz herhangi bir değer mevcut değil, sadece şekli tanımlı bir tensor.
# Tensorun karesini alan basit bir graph.
x = tf.placeholder(tf.float32, shape=[3])
y = tf.square(x)

with tf.Session() as sess:
    # y değişkeni evaluate edilirken kullanacğı değerleri feedliyoruz.
    print(sess.run(y, {x: [1.0, 2.0, 3.0]})  # => "[1.0, 4.0, 9.0]"
    print(sess.run(y, {x: [0.0, 0.0, 5.0]})  # => "[0.0, 0.0, 25.0]"

    # Burada `tf.errors.InvalidArgumentError` hatasını verir. 
    # Çünkü tf.palceholder a bağlı bir tensor için feed gerekiyor.
    sess.run(y)

    # Burada da `ValueError' hatasını verir. Çünkü verilen feed 
    # x placeholderın şekline uymuyor.
    sess.run(y, {x: 37.0})

tf.Session.run metodu bir de options argumanı alır. Bu parametre ile bir execution için bir takım ayarlamalar yapılabilir, ayrıca bir metadata tanımlayarak execution sırasında bilgi toplanabilir. Küçük bir örnek daha:

y = tf.matmul([[37.0, -23.0], [1.0, 4.0]], tf.random_uniform([2, 2]))

with tf.Session() as sess:
  # options değişkeni tanımlanıyor
  options = tf.RunOptions()
  options.output_partition_graphs = True
  options.trace_level = tf.RunOptions.FULL_TRACE

  # Return edilecek metadata için bir container oluşturulyor
  metadata = tf.RunMetadata()

  sess.run(y, options=options, run_metadata=metadata)

  # metadataya doldurulan subgraph bilgisi ekrana bastırılıyor
  print(metadata.partition_graphs)

  # Her operation için geçen süreler ekrana bastırılır.
  print(metadata.step_stats)

Evet benim anlatacaklarım bu kadar. Elimden geldiğince yapıyı anlamaya ve anlatmaya çalıştım. Elbette yanlışlarım olmuştur. Bunları belirtirseniz bana ve bu yazı okuyacaklara faydanız olur. Farklı kaynaklara, özellikle Tensorflow’un kendi dökümantasyonuna, bakmanız çok iyi olur. Umarım artık bir Tensorflow modeli görünce ne yaptığını analayabilirsiniz. Daha fazla derinleşmelk için bir kaç model öreneği yapmak gerekiyor.

Destekleyici Kaynaklar:
https://web.stanford.edu/class/cs224n/lectures/cs224n-2017-tensorflow.pdf
https://www.tensorflow.org/programmers_guide/
https://cs224d.stanford.edu/lectures/CS224d-Lecture7.pdf