顯示具有 AI 標籤的文章。 顯示所有文章
顯示具有 AI 標籤的文章。 顯示所有文章

2018年3月29日 星期四

TensorFlow的第一步

請參考原始資料:
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:

# Define the input feature: total_rooms.
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()

predictionstargets
count17000.017000.0
mean0.1207.3
std0.1116.0
min0.015.0
25%0.1119.4
50%0.1180.4
75%0.2265.0
max1.9500.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
)


2017年6月12日 星期一

Google Video Intelligence 學習筆記

Google Video Intelligence 學習筆記

除了前面所述 Google Cloud vision,透過靜態照片來由Google Cloud Vision AI 來辨識之外,Google另一項影像辨識功能,即透過影片(video) 來進行影像辨識。

在這篇有介紹如何進行Google Video Intelligence 的 快速入門。

在這篇的範例,需要先安裝Google Cloud SDK,再請先安裝。

開啟一個專案

  1. 在Google Cloud Platform 內,先建立一個新的專案。
  2. 到 API 管理介面,啟用 Google Video Intelligence API
  3. 然後在 API 管理介面內,點選「憑證」,建立API 金鑰,它會跳出一個視窗,告訴你在使用此API 時,用 key=API_KEY 來傳送金鑰,所以記得要先把你的API 金鑰剪下來,貼在你的文字檔裡。如下圖:

設定授權

在你安裝好 Google Cloud SDK 後,在其目錄下就會有 cloud 這支程式:
  1. 建立一個服務帳號,叫 quickstart:
  1. gcloud iam service-accounts create quickstart

  2. 建立 service account key file,其中your-project-123 是你剛才建立的專案名稱全名(即加上 - 後面的數字串):
  3. gcloud iam service-accounts keys create key.json \
    --iam-account quickstart@your-project-123.iam.gserviceaccount.com
  4. 授權給你的service account,並把你的service account key file 位置傳送過去
  5. gcloud auth activate-service-account --key-file key.json
  6. 取得授權,並將它顯示在螢幕上:
  7. gcloud auth print-access-token
你會看到程式大概五秒之後會顯示一長串亂碼,那其實就是你的key,也就是上面圖示顯示的那塊。

進行 Video 辨識請求

  1. 用文字編輯器,將下列文字copy 到你的文字檔裡,用來產生一個 JSON 要求檔,就叫 request.json。但要記得,將你的檔案copy 到你的 google cloud storage 內。目前google video intelligence 只支援將影片上傳到其google cloud storage 內做辨識,並不支援其他任何方式(如 streaming)。像下面的範例就是在cloud storage 建立一個 video 目錄,再把 chicago.mp4 上傳到這個video 目錄下。
  2. {
       "inputUri":"gs://cloud-ml-sandbox/video/chicago.mp4",
       "features": [
           "LABEL_DETECTION"
       ]
    }
    
  3. 利用 curl 指令來產生影像辨識要求 (videos:annotate),將下方的 ACCESS_TOKEN h利用剛才印出的那一長串亂碼(即access token) 取代,其餘照抄(下面這指令全在同一行內, \表連續行):
  4. curl -s -k -H 'Content-Type: application/json' \
        -H 'Authorization: Bearer ACCESS_TOKEN' \
        'https://videointelligence.googleapis.com/v1beta1/videos:annotate' \
        -d @request.json
    Video intelligence API 會產生一個 operation 以處理你的辨識要求。上述指令下完會,會顯示它產生的 operation name:
      {
        "name": "us-west-18358601230245040268"
      }
      
    1. 這時Google 已經開始在分析你的影片,你可以傳遞operation name 並透過 v1.operations  來取得分析結果:
    2. curl -s -k -H 'Content-Type: application/json' \
          -H 'Authorization: Bearer ACCESS_TOKEN' \
          'https://videointelligence.googleapis.com/v1/operations/OPERATION_NAME'
      你會看到Google 回應你分析的結果,如果分析尚未完成,那在 done 這個值會是 false:
      {
        "name": "OPERATION_NAME",
        "metadata": {
          "@type": "type.googleapis.com/google.cloud.videointelligence.v1beta1.Annota
      tionProgressMetadata",
          "progressMetadata": [
            {
              "inputUri": "gs://cloud-ml-sandbox/video/chicago.mp4",
              "progressPercent": 0,
              "startTime": "2016-09-22T21:41:56.766091Z",
              "lastUpdateTime": "2016-09-22T21:42:03.889743Z"
            }
          ]
        },
        "done": false,
        ...
      }
      
    在分析完所有資料後,你再下一次上述指令,就可以看到Google Video intelligence 對你的影片做的完整分析內容。其中 description 欄表示它判斷可能的物件名稱,confidence 表信心值,或簡單說,它猜此物件的正確率大約是多少。

    結論


    基本上Google Video intelligence 可以辨識出的物件仍然有限,尤其影片不清楚時,所以它的信心值都不高。它目前可以做物件分析,臉部分析,標題分析和場景變換的辨認。它可以用來判斷你的影片內出現了那些東西,但無法很精確地辨識出人臉或(誰)出現在影片裡。但Apple 的 照片 程式可以將類似的人臉整合成一個群組,再給人類進行更正確的判斷是否為同一個人。我想,應該要做到這樣的程度才夠吧。而且,影片還要上傳到google storage才能辨識,還不夠方便。不過,Google 也強調,這是beta,還沒算正試的服務,就玩玩看囉。