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)
feature
和labels
必須是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