原創 lightcity 光城 2019-02-02
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。
在上面的代碼我曾經使用過資料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
每個圖像都是一個28x28陣列,被展平為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
寫在最後
本節學習來源斯坦福大學cs20課程,有關自學與組隊學習筆記,将會放于github倉庫與本公衆号釋出,歡迎大家star與轉發,收藏!
cs20是一門對于深度學習研究者學習Tensorflow的課程,今天學習了三節,非常有收獲,并且陸續将内容寫入jupytebook notebook中,有關這個源代碼及倉庫位址,大家可以點選閱讀原文或者直接複制下面連結!