https://colab.research.google.com/notebooks/mlcc/first_steps_with_tensor_flow.ipynb?hl=en#scrollTo=EL8-9d4ZJNR7
(我對原資料的理解不一定正確,請自行修正)
要運用tensorflow 的第步驟如下:
第一步:定義特性及設定特性行位
首先我們要告訴 tensorflow 所謂的 「特性行位」feature column是資料內的那一行。tensorflow 才會知道從那些資料去進行分析。而所謂的特性行位的資料行,大致分成兩種:
一是類別型資料(Catagorical Data),例如這行的資料都是形容詞:大中小、紅黃綠、方扁圓 等等。
另一種是數字型資料(Numerical Data),例如面積:30米平方、60米平方、90米平方,RGB:(200,179,87),時間差:20秒,90秒,45秒 等等很明確的數字資料。
在TensorFlow 內,透過 feature column 的結構來指定特性行位,而這個feature column 只儲存特性行位的此行的說明,並不會儲存此行的所有資料。
在本範例,我們只用資料內的一行 total_rooms 來做為特性行位,下面兩行,第一行是把其中的 total_rooms 從 california_housing_dataframe 取出來,存成 my_feature, 第二行則是將 my_feature指定給feature_column,並設定為數字型資料numeric_column:
my_feature = california_housing_dataframe[["total_rooms"]]
# Configure a numeric feature column for total_rooms.
feature_columns = [tf.feature_column.numeric_column("total_rooms")]
你可以參考 tensorflow 對 feature_column.numeric_column 的說明,它其實包含了其他的參數,但在這裡,先簡化,用一行來示範即可。
第二步:定義目標
再來我們要定義目標,即,要估算的的目標是為何,給了特性和目標給tensorflow去學習,tensorflow 才可以依據新的feature 來推算目標值可能為何。在這範例中,我們要估的是 Median_house_value:
# Define the label.
targets = california_housing_dataframe["median_house_value"]
第三步:設定線性迴歸(LinearRegressor)
在學習使用tensorflow 的範例裡,我們用較單純的線性迴歸方法來做學習。並使用 GradientDescentOptimizer (即使用 Mini-Batch Stochastic Gradient Descent(SGD)). learning_rate 參數可以控制推估步驟的大小。同時我們也使用透過 clip_gradients_by_norm 函式來使用 gradient clipping方法,以避免誤差越算越大,造成估算錯誤。
# Use gradient descent as the optimizer for training the model.
my_optimizer=tf.train.GradientDescentOptimizer(learning_rate=0.0000001)
my_optimizer = tf.contrib.estimator.clip_gradients_by_norm(my_optimizer, 5.0)
# Configure the linear regression model with our feature columns and optimizer.
# Set a learning rate of 0.0000001 for Gradient Descent.
linear_regressor = tf.estimator.LinearRegressor(
feature_columns=feature_columns,
optimizer=my_optimizer
)
第四步:設定輸入的部分
在匯入 California housing data 到 LinearRegressor 函式內之前,我們必須先定設定好輸入函式的部分,好告訴 tensorflow 如何處理匯進來的資料,好在學習的過程中進行如何分批次,打散資料,重覆這些動作等等。
記得嗎?我們在第一步驟只是先定義特性行的名稱,資料並還沒匯入喔。
所以,首先,我們必須把pandas 的 特性資料 轉成 numpy 的 array 型式的 dict. 然後我們就可以用 TensorFlow 的 Dataset API 來建構 dataset 物件,再根據給定的 batch_size 來將資料分散成幾個群組(batches), 以便用來重覆執行每次的學習(num_epochs)。(如果指定 num_epochs=None 給 repeat(), 那輸入資料將會被無止䀆地重覆?
再來,如果 shuffle 設為 True, 那在訓練期間的資料匯入時就會被打散,這樣資料會比較平均一些。buffer_size 參數則是用來指定打散後匯進 dataset 的資料量大小。
最後,我們的輸入函式會建構一個 iterator 給 dataset, 並傳回下一個要處理的批次資料給 LinearRegressor.
def my_input_fn(features, targets, batch_size=1, shuffle=True, num_epochs=None):
"""Trains a linear regression model of one feature.
Args:
features: pandas DataFrame of features
targets: pandas DataFrame of targets
batch_size: Size of batches to be passed to the model
shuffle: True or False. Whether to shuffle the data.
num_epochs: Number of epochs for which data should be repeated. None = repeat indefinitely
Returns:
Tuple of (features, labels) for next data batch
"""
# Convert pandas data into a dict of np arrays.
features = {key:np.array(value) for key,value in dict(features).items()}
# Construct a dataset, and configure batching/repeating
ds = Dataset.from_tensor_slices((features,targets)) # warning: 2GB limit
ds = ds.batch(batch_size).repeat(num_epochs)
# Shuffle the data, if specified
if shuffle:
ds = ds.shuffle(buffer_size=10000)
# Return the next batch of data
features, labels = ds.make_one_shot_iterator().get_next()
return features, labels
第五步:開始訓練
至此,我們可以準備呼叫在 linear_regressor 的 train() 來訓練了。_ = linear_regressor.train(
input_fn = lambda:my_input_fn(my_feature, targets),
steps=100
)
第六步:評估此模型
我們可以開始針對訓練來測試訓練結果,看看我們的模型是否符合我們的訓練設定。
# Create an input function for predictions.
# Note: Since we're making just one prediction for each example, we don't
# need to repeat or shuffle the data here.
prediction_input_fn =lambda: my_input_fn(my_feature, targets, num_epochs=1, shuffle=False)
# Call predict() on the linear_regressor to make predictions.
predictions = linear_regressor.predict(input_fn=prediction_input_fn)
# Format predictions as a NumPy array, so we can calculate error metrics.
predictions = np.array([item['predictions'][0] for item in predictions])
# Print Mean Squared Error and Root Mean Squared Error.
mean_squared_error = metrics.mean_squared_error(predictions, targets)
root_mean_squared_error = math.sqrt(mean_squared_error)
print ("Mean Squared Error (on training data): {}".format(mean_squared_error))
print ("Root Mean Squared Error (on training data): {}".format(root_mean_squared_error))
Mean Squared Error (on training data): 56367.025
Root Mean Squared Error (on training data): 237.417
這是好的估算模型嗎?我們怎麼判定誤差是多少才算 好?
Mean Squared Error(MSE 均方差) 並不好判讀,所以可以改成 Root Mean Squared Error(RMSE 均方差根) 來判讀,均方差根的好處是不會受範圍的影響。
我們可以比較一下 target 中最大和最小值的 median_house_value 的 RMSE 的差異:
min_house_value = california_housing_dataframe["median_house_value"].min()
max_house_value = california_housing_dataframe["median_house_value"].max()
min_max_difference = max_house_value - min_house_value
print ("Min. Median House Value: {}".format(min_house_value))
print ("Max. Median House Value: {}".format(max_house_value))
print ("Difference between Min. and Max.: {}".format(min_max_difference))
print ("Root Mean Squared Error: {}".format(root_mean_squared_error))
Min. Median House Value: 14.999
Max. Median House Value: 500.001
Difference between Min. and Max.: 485.002
Root Mean Squared Error: 237.417
我們的誤差值大約落在目標值的一半之間。
讓我們再來改個基本架構,看能不能減少誤差。
首先來看看我們的估計值有多接近目標值:
calibration_data = pd.DataFrame()
calibration_data["predictions"] = pd.Series(predictions)
calibration_data["targets"] = pd.Series(targets)
calibration_data.describe()
| predictions | targets | |
|---|---|---|
| count | 17000.0 | 17000.0 |
| mean | 0.1 | 207.3 |
| std | 0.1 | 116.0 |
| min | 0.0 | 15.0 |
| 25% | 0.1 | 119.4 |
| 50% | 0.1 | 180.4 |
| 75% | 0.2 | 265.0 |
| max | 1.9 | 500.0 |
這樣的資訊(說實在的,我不懂)也許夠用了,我們來把它視覺化看看。
首先,我們胡亂取一些sample 的資料,好畫一張看得懂的分佈圖。
sample = california_housing_dataframe.sample(n=300)
然後,再用前面(?)學的步驟,將分佈狀況和特性權重 把它畫在分佈圖上,線會用紅色呈現。
# Get the min and max total_rooms values.
x_0 = sample["total_rooms"].min()
x_1 = sample["total_rooms"].max()
# Retrieve the final weight and bias generated during training.
weight = linear_regressor.get_variable_value('linear/linear_model/total_rooms/weights')[0]
bias = linear_regressor.get_variable_value('linear/linear_model/bias_weights')
# Get the predicted median_house_values for the min and max total_rooms values.
y_0 = weight * x_0 + bias
y_1 = weight * x_1 + bias
# Plot our regression line from (x_0, y_0) to (x_1, y_1).
plt.plot([x_0, x_1], [y_0, y_1], c='r')
# Label the graph axes.
plt.ylabel("median_house_value")
plt.xlabel("total_rooms")
# Plot a scatter plot from our data sample.
plt.scatter(sample["total_rooms"], sample["median_house_value"])
# Display graph.
plt.show()
嗯嗯,不太懂那條紅色代表 RMSE 的什麼意思⋯⋯ 😅
再進階一下:
調整這個模型的一些參數⋯⋯
def train_model(learning_rate, steps, batch_size, input_feature="total_rooms"):
"""Trains a linear regression model of one feature.
Args:
learning_rate: A `float`, the learning rate.
steps: A non-zero `int`, the total number of training steps. A training step
consists of a forward and backward pass using a single batch.
batch_size: A non-zero `int`, the batch size.
input_feature: A `string` specifying a column from `california_housing_dataframe`
to use as input feature.
"""
periods = 10
steps_per_period = steps / periods
my_feature = input_feature
my_feature_data = california_housing_dataframe[[my_feature]]
my_label = "median_house_value"
targets = california_housing_dataframe[my_label]
# Create feature columns
feature_columns = [tf.feature_column.numeric_column(my_feature)]
# Create input functions
training_input_fn = lambda:my_input_fn(my_feature_data, targets, batch_size=batch_size)
prediction_input_fn = lambda: my_input_fn(my_feature_data, targets, num_epochs=1, shuffle=False)
# Create a linear regressor object.
my_optimizer = tf.train.GradientDescentOptimizer(learning_rate=learning_rate)
my_optimizer = tf.contrib.estimator.clip_gradients_by_norm(my_optimizer, 5.0)
linear_regressor = tf.estimator.LinearRegressor(
feature_columns=feature_columns,
optimizer=my_optimizer
)
# Set up to plot the state of our model's line each period.
plt.figure(figsize=(15, 6))
plt.subplot(1, 2, 1)
plt.title("Learned Line by Period")
plt.ylabel(my_label)
plt.xlabel(my_feature)
sample = california_housing_dataframe.sample(n=300)
plt.scatter(sample[my_feature], sample[my_label])
colors = [cm.coolwarm(x) for x in np.linspace(-1, 1, periods)]
# Train the model, but do so inside a loop so that we can periodically assess
# loss metrics.
print "Training model..."
print "RMSE (on training data):"
root_mean_squared_errors = []
for period in range (0, periods):
# Train the model, starting from the prior state.
linear_regressor.train(
input_fn=training_input_fn,
steps=steps_per_period
)
# Take a break and compute predictions.
predictions = linear_regressor.predict(input_fn=prediction_input_fn)
predictions = np.array([item['predictions'][0] for item in predictions])
# Compute loss.
root_mean_squared_error = math.sqrt(
metrics.mean_squared_error(predictions, targets))
# Occasionally print the current loss.
print " period %02d : %0.2f" % (period, root_mean_squared_error)
# Add the loss metrics from this period to our list.
root_mean_squared_errors.append(root_mean_squared_error)
# Finally, track the weights and biases over time.
# Apply some math to ensure that the data and line are plotted neatly.
y_extents = np.array([0, sample[my_label].max()])
weight = linear_regressor.get_variable_value('linear/linear_model/%s/weights' % input_feature)[0]
bias = linear_regressor.get_variable_value('linear/linear_model/bias_weights')
x_extents = (y_extents - bias) / weight
x_extents = np.maximum(np.minimum(x_extents,
sample[my_feature].max()),
sample[my_feature].min())
y_extents = weight * x_extents + bias
plt.plot(x_extents, y_extents, color=colors[period])
print "Model training finished."
# Output a graph of loss metrics over periods.
plt.subplot(1, 2, 2)
plt.ylabel('RMSE')
plt.xlabel('Periods')
plt.title("Root Mean Squared Error vs. Periods")
plt.tight_layout()
plt.plot(root_mean_squared_errors)
# Output a table with calibration data.
calibration_data = pd.DataFrame()
calibration_data["predictions"] = pd.Series(predictions)
calibration_data["targets"] = pd.Series(targets)
display.display(calibration_data.describe())
print "Final RMSE (on training data): %0.2f" % root_mean_squared_error
調整一:
調整參數以改進耗損並接近目標分布狀況。 如果⋯⋯超過跑超過5分鐘以上,表示 RMSE 被你操掛了,要重新調整一下參數。
train_model(
learning_rate=0.00001,
steps=100,
batch_size=1
)

