TensorFlow線性回歸與邏輯回歸實戰

  • 2019 年 10 月 5 日
  • 筆記

TensorFlow線性回歸與邏輯回歸實戰

議程

  • Review
  • Linear regression on birth/life data
  • Control Flow
  • tf.data
  • Optimizers, gradients
  • Logistic regression on MNIST
  • Loss functions

一、TensorFlow線性回歸


回顧

計算圖

TensorFlow將計算的定義與其執行分開

階段1:組裝圖表

階段2:使用會話在圖中執行操作。

TensorBoard

import tensorflow as tf  x = 2  y = 3  add_op = tf.add(x, y)  mul_op = tf.multiply(x, y)  useless = tf.multiply(x, add_op)  pow_op = tf.pow(add_op, mul_op)  writer=tf.summary.FileWriter('./graphs',tf.get_default_graph())  with tf.Session() as sess:      z = sess.run(pow_op)

tf.constant and tf.Variable

常量值存儲在圖形定義中

會話分配記憶體來存儲變數值

tf.placeholder and feed_dict

使用字典(feed_dict)將值提供給佔位符

易於使用但性能不佳

避免懶載入

  • 分離圖形的組合和執行操作
  • 使用Python屬性確保函數僅在第一次調用時載入

在TensorFlow中的線性回歸

數據與模型概要

建模之間的線性關係:

  • 因變數Y.
  • 解釋變數X.

世界發展指標數據集

  • X: 出生率
  • Y: 預期壽命

190 國家

想要:找到X和Y之間的線性關係,從X預測Y.

模型:參考: Y_predicted = w * X + b

均方誤差: E[(y - y_predicted)2]

所需數據與程式碼:

data/birth_life_2010.txt  examples/03_linreg_starter.py  

階段1:組裝我們的圖表

第一步:讀數據

import os  os.environ['TF_CPP_MIN_LOG_LEVEL']='2'  import numpy as np  %matplotlib inline  import pandas as pd  
第一種方式讀取(官方)
def read_data(filename):      '''      讀取birth_life_2010.txt 數據      data:返回numpy數組數據      n_samples:例子的數量      '''      # 去掉head      text = open(filename, 'r').readlines()[1:]      # 去掉每一行末尾的換行符n,並以製表符t進行分隔      data = [line[:-1].split('t') for line in text]      # 提取出生率      births = [float(line[1]) for line in data]      # 提取預期壽命      lifes = [float(line[2]) for line in data]      # 變成[(),()]數據      data = list(zip(births, lifes))      # 統計數據量      n_samples = len(data)      # 數據轉換為numpy的ndarray類型      data = np.asarray(data, dtype=np.float32)      return data, n_samples  
data,n_samples=read_data('birth_life_2010.txt')  data  

輸出:

array([[ 1.822   , 74.82825 ],         [ 3.869   , 70.81949 ],         ...         [ 5.287   , 55.585587],         [ 5.443   , 50.65366 ]], dtype=float32)  n_samples  

輸出:

190  
第二種方式讀取
# 第二種方式讀取  def read_data(file_name):      data = pd.read_table('birth_life_2010.txt')      births = data['Birth rate']      lifes = data['Life expectancy']      data = list(zip(births,lifes))      n_samples = len(data)      data = np.asarray(data, dtype=np.float32)      return data,n_samples  data,n_samples=read_data('birth_life_2010.txt')  data,n_samples  

輸出:

(array([[ 1.822   , 74.82825 ],          [ 3.869   , 70.81949 ],          ...          [ 5.287   , 55.585587],          [ 5.443   , 50.65366 ]], dtype=float32), 190)  

第2步:為輸入和標籤創建佔位符

# tf.placeholder(dtype, shape=None, name=None)  X,Y=None,None  X = tf.placeholder(dtype=tf.float32)  Y = tf.placeholder(dtype=tf.float32)  

第3步:創建權重和偏置

# tf.get_variable(name,shape=None,dtype=None,initializer=None,)  # w,b,X,Y都是標量,shape=()可設置為shape=[]  w,b = None,None  w = tf.get_variable(name='weght',shape=(),initializer=tf.zeros_initializer())  b = tf.get_variable(name='bias',shape=(),initializer=tf.zeros_initializer())  

第4步:預測

Y_predicted = None  Y_predicted = w * X + b  

第5步:指定損失函數

loss = None  loss = tf.square(Y - Y_predicted, name='loss')  

第6步:創建優化器

opt = tf.train.GradientDescentOptimizer(learning_rate=0.001)  optimizer = opt.minimize(loss)  import time  start = time.time()  

階段2:訓練我們的模型

第7步:初始化及TensorBoard

with tf.Session() as sess:      # 初始化變數      sess.run(tf.global_variables_initializer())      # tensorboard      writer = tf.summary.FileWriter('./graphs/linear_reg',sess.graph)      ...  

第8步:訓練模型100個epochs

with tf.Session() as sess:      # 初始化變數      sess.run(tf.global_variables_initializer())      # tensorboard      writer = tf.summary.FileWriter('./graphs/linear_reg',sess.graph)      # trian the model for 100 epoch      for i in range(100):          # 初始化每一次的loss          total_loss=0          # 每一次,一批批訓練          for x,y in data:              # 需要運行優化函數optimizer與loss, Tensorflow 會自動更新weight 和bias 兩個變數              _,loss_ = sess.run([optimizer,loss],feed_dict={X:x,Y:y})              total_loss += loss_          print('Epoch {0}:{1}'.format(i,total_loss/n_samples))      writer.close()  

輸出:

Epoch 0:1661.8637834631543  Epoch 1:956.3224148609137  ...  Epoch 98:30.0349335548615  Epoch 99:30.03552558278714  

第9步:輸出w和b的值

with tf.Session() as sess:      # 初始化變數      sess.run(tf.global_variables_initializer())      # tensorboard      writer = tf.summary.FileWriter('./graphs/linear_reg',sess.graph)      # trian the model for 100 epoch      for i in range(100):          # 初始化每一次的loss          total_loss=0          # 每一次,一批批訓練          for x,y in data:              # 需要運行優化函數optimizer與loss, Tensorflow 會自動更新weight 和bias 兩個變數              _,loss_ = sess.run([optimizer,loss],feed_dict={X:x,Y:y})              total_loss += loss_          print('Epoch {0}:{1}'.format(i,total_loss/n_samples))      writer.close()      # 第9步:輸出w和b的值      w_out,b_out = None,None      w_out, b_out = sess.run([w, b])  

輸出:

Epoch 0:1661.8637834631543  Epoch 1:956.3224148609137  ...  Epoch 98:30.0349335548615  Epoch 99:30.03552558278714  

第10步:輸出耗時

print('Took: %f seconds' %(time.time() - start))  print('last value of loss, w, b: {0}, {1}, {2}'.format(total_loss/n_samples, w_out, b_out))  

輸出:

Took: 25.186522 seconds  last value of loss, w, b: 30.03552558278714, -6.07021427154541, 84.92951202392578  

第11步:可視化

import matplotlib.pyplot as plt  plt.plot(data[:,0], data[:,1], 'bo', label='Real data')  plt.plot(data[:,0], data[:,0] * w_out + b_out, 'r', label='Predicted data')  plt.legend()  

輸出

Huber loss

Huber loss是為了增強平方誤差損失函數(squared loss function)對雜訊(或叫離群點,outliers)的魯棒性提出的。

對異常值的魯棒性,如果預測值和實際值之間的差異很小,則將其平方;如果它很大,取其絕對值。

定義:

控制流程

在TensorFlow中,tf.cond()類似於c語言中的if…else…,用來控制數據流向,但是僅僅類似而已,其中差別還是挺大的。

格式:tf.cond(pred, fn1, fn2, name=None)

def huber_loss(label, prediction, delta=14.0):      residual = tf.abs(label - prediction)      def f1(): return 0.5*tf.square(residual)      def f2(): return delta*residual-0.5*tf.square(delta)      return tf.cond(residual < delta, f1,f2)  # cond函數分為true和false兩種情況。在許多情況下,使用函數tf.case。  

tf.data

在上面的程式碼我曾經使用過數據placeholder。但是佔位符是一種古老的方式,關於這種方法有各種各樣的意見。看來有利於的是,它是一個點,缺點在於它可以很容易地處理數據外的TF較慢處理應被視為一個單獨的執行緒中的數據,和數據瓶頸。因此,這個問題得以解決tf.data。

如何使用tf.data?

tf.data.Dataset.from_tensor_slices((feature, labels))  tf.data.Dataset.from_generator(gen, output_types, output_shapes)  

featurelabels必須是Tensor數據類型。但是,由於張量數據類型與numpy數據類型相同,因此可以包含numpy數據類型。

# 換句話說,如果您從上面的模型中讀取數據為tf.data,您可以寫:  data,n_samples=read_data('birth_life_2010.txt')  dataset = tf.data.Dataset.from_tensor_slices((data[:,0], data[:,1]))  dataset  

輸出:

<TensorSliceDataset shapes: ((), ()), types: (tf.float32, tf.float32)>  
print(dataset.output_types) # >> (tf.float32, tf.float32)  print(dataset.output_shapes) # >> (TensorShape([]), TensorShape([]))  
(tf.float32, tf.float32)  (TensorShape([]), TensorShape([]))  

tf.data.Dataset有幾種方法,你可以直接讀取數據文件Tensorflow文件格式分析器。

tf.data.TextLineDataset(filenames) 將文件的每一行讀作一個數據。它主要用於讀取csv文件和機器翻譯領域。

tf.data.FixedLengthRecordData(filenames)它主要用於固定長度數據。數據作為一個數據被接收預定長度。經常使用的地方也經常用於由固定長度組成的數據中。例如,它用於讀取諸如CIFAR數據或ImageNet數據之類的內容。

tf.data.TFRecordDataset(filenames)用於tfrecord格式的數據。

我看到了如何讀取數據。現在讓我們看一下使用數據。在現有程式碼中,我們for通過語句逐個使用數據的值。tf.data.Iterator使得逐個使用數據變得更加容易。

tf.data.Iterator

iterator = dataset.make_one_shot_iterator()

通過數據集只迭代一次。無需初始化。

iterator = dataset.make_initializable_iterator()

根據需要迭代數據集。需要初始化每個epoch。

iterator = dataset.make_one_shot_iterator()  X, Y = iterator.get_next()  
with tf.Session() as sess:      print(sess.run([X, Y]))        # >> [1.822, 74.82825]      print(sess.run([X, Y]))        # >> [3.869, 70.81949]      print(sess.run([X, Y]))        # >> [3.911, 72.15066]  
[1.822, 74.82825]  [3.869, 70.81949]  [3.911, 72.15066]  

處理TensorFlow中的數據

dataset = dataset.shuffle(1000)  dataset = dataset.repeat(100)  dataset = dataset.batch(128)  dataset = dataset.map(lambda x: tf.one_hot(x, 10)) # convert each elem of dataset to one_hot vector  

我們應該使用tf.data?

對於原型設計,feed dict可以更快更容易編寫(pythonic)

當您有複雜的預處理或多個數據源時,tf.data很難使用

NLP數據通常只是一個整數序列。在這種情況下,將數據傳輸到GPU非常快,因此tf.data的加速並不是那麼大

優化

使用優化器非常簡單。然而只有幾行程式碼可以方便地使用(差分,更新)複雜的配置的優化器。

optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.01).minimize(loss)  _, l = sess.run([optimizer, loss], feed_dict={X: x, Y:y})  

會話查看損失所依賴的所有可訓練變數並更新它們

tf.Variable(initial_value=None, trainable=True,...)

優化程式會自動計算和更新衍生值。因此,它適用於所有相關變數。在某些情況下,可能存在不應更新的變數。在這種變數的情況下,trainable=False通過僅將其指定為選項,可以很容易地將其設置為不訓練

除了上面使用的GD opmizer之外,還提供了各種其他優化器作為張量流函數。以下是優化器列表。

  • tf.train.Optimizer
  • tf.train.GradientDescentOptimizer
  • tf.train.AdadeltaOptimizer
  • tf.train.AdagradOptimizer
  • tf.train.AdagradDAOptimizer
  • tf.train.MomentumOptimizer
  • tf.train.AdamOptimizer
  • tf.train.FtrlOptimizer
  • tf.train.ProximalGradientDescentOptimizer
  • tf.train.ProximalAdagradOptimizer
  • tf.train.RMSPropOptimizer

二、TensorFlow邏輯回歸


數據集:MNIST Database

每個影像都是一個28×28陣列,被展平為1-d張量,大小為784

X: 手寫數字影像 Y: 數字值

任務:識別圖中的數字

模型:Y_predicted = softmax(X * w + b)

損失函數(交叉熵損失): -log(Y_predicted)

1.處理數據

import utils  import tensorflow as tf  import time  learning_rate = 0.01  batch_size = 128  n_epochs = 30  n_train = 60000  n_test = 10000    mnist_folder = 'data/mnist'  utils.download_mnist(mnist_folder)  train, val, test = utils.read_mnist(mnist_folder, flatten=True)    train_data = tf.data.Dataset.from_tensor_slices(train)  train_data = train_data.shuffle(10000) #  train_data = train_data.batch(batch_size)    test_data = tf.data.Dataset.from_tensor_slices(test)  test_data = test_data.batch(batch_size)  

2.創建一個迭代器並確定如何初始化它。

iterator = tf.data.Iterator.from_structure(train_data.output_types,train_data.output_shapes)  img,label = iterator.get_next()  train_init = iterator.make_initializer(train_data)  test_init = iterator.make_initializer(test_data)  

3.並生成模型的參數w和b。設置形狀以適合img大小。然後,w被初始化為具有均值0和標準差方差0.01的正態分布,並且b被初始化為0。

w = tf.get_variable(name='weight', shape=(784,10), initializer=tf.random_normal_initializer(0,0.01))  b = tf.get_variable(name='bias', shape=(1,10), initializer=tf.zeros_initializer())  

4.定義logit和softmax函數並定義損失函數。

logits = tf.matmul(img,w) + b    entropy = tf.nn.softmax_cross_entropy_with_logits_v2(logits=logits, labels=label, name='entropy')  loss = tf.reduce_mean(entropy, name = 'loss')  

5.優化器使用Adam優化器。

optimizer = tf.train.AdamOptimizer(learning_rate).minimize(loss)  

6.定義預測操作,確認預測是否正確,以及精度計算操作。

preds = tf.nn.softmax(logits)  correct_preds = tf.equal(tf.argmax(preds, 1), tf.argmax(label, 1))  accuracy = tf.reduce_sum(tf.cast(correct_preds, tf.float32))  

7.現在讓我們可視化及定義session內容。

writer = tf.summary.FileWriter('./graphs/logreg', tf.get_default_graph())    gpu_options = tf.GPUOptions(per_process_gpu_memory_fraction=0.333)  if 'session' in locals() and session is not None:      print('Close interactive session')      session.close()  with tf.Session(config=tf.ConfigProto(gpu_options=gpu_options)) as sess:      start_time = time.time()      # 初始化變數      sess.run(tf.global_variables_initializer())      # 訓練      for i in range(n_epochs):          sess.run(train_init) # drawing samples from train_data          total_loss = 0          n_batches = 0          try:              while True:                  _, l = sess.run([optimizer, loss])                  total_loss += l                  n_batches += 1          except tf.errors.OutOfRangeError:              pass          print('Average loss epoch {0}: {1}'.format(i, total_loss/n_batches))      print('Total time: {0} seconds'.format(time.time() - start_time))        # test the model      sess.run(test_init) # drawing samples from test_data      total_correct_preds = 0      try:          while True:              accuracy_batch = sess.run(accuracy)              total_correct_preds += accuracy_batch      except tf.errors.OutOfRangeError:          pass        print('Accuracy {0}'.format(total_correct_preds/n_test))  writer.close()  

輸出:

Average loss epoch 0: 0.3655088067747826  ...  Average loss epoch 29: 0.25185961714664173  Total time: 23.884480476379395 seconds  Accuracy 0.917