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

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
)


2018年3月20日 星期二

程式設計的開發者介面

半路出家的和尚,實在說不出什麼哲理。
但既然每次學習都要用到,還是自己記錄一下好了。
初學python ,就是使用python install 後的 launch. 但launch 的功能太兩光,所以上網找看看有沒有免費又好用的IDE(Interactive Development Environment), 中文稱為「互動式開發環境」。沒有IDE時,我們必須先在某個editor 編輯好程式後,再在editor 外的環境進行編釋或執行,editor 一般也沒有針對特殊程式語言進行關鍵字標示或語法錯誤的提示,因此非常地不方便,但這就是以前的開發程式的環境。後來有了IDE的概念後,程式開發變得比較友善了。
python 下的開發環境也有不少,包括像pyCharm 等,但大多要$$,在這個自由的世界,當然要找個自由的軟體,於是找到了 Atom , 這是一個相容於Windows/Mac OS/Linux 的自由軟體。當然MS 也提供了一個免費的IDE Visual Studio Code, 看來和 Atom 很類似,但因為對MS 的印象不好,所以沒試過VSC。

Atom 提供了自行修改的靈活度,可讓User 自行調整相關參數,以更符合自己的使用需求。同時它也提供了內建的套件管理,這些套件都各有優點,包括將python 語法錯誤特別標示的功能,python 自動定位的功能,將程式編列更整齊的套件等等,讓我在coding 時,可以一目瞭然。同時也支援 GitHub, 讓你可以做好版本管理,但我還是沒搞懂怎麼運作。最近的功能是提供協同作業,讓團隊可以一起編輯程式,這個很cool,只是我都是一個人作業,沒能用上。

在python 上,很多machine learning 或AI 的學習都支援python, 而其中另一個介面是 Jupyter。但我不想再裝一套介面⋯⋯畢竟6 年前MBP HD 才 256G,能減少重覆功能的程式是最好的。還好,Atom 也提供了 Jupyter 類似功能的套件 - Hygrogen。 Hydrogen 提供了在Atom 內類似Jupyter 的即時觀看結果,和圖形結果的介面內顯示,讓你可以將mathlab 的圖形直接在語言窗格內呈現,不用再另外跳出一個視窗。也提供了 cell 的執行,即單一或幾行的 程式執行,省去每次都要重頭執行的困擾。


我的Atom 介面



還有一個特別的套件 叫 platformio 要特別介紹一下,這是一個支援多種MCU 開發板的開發介面,不用再使用Arduino 的不方便介面,而且除了Arduino 還支援 ESP8266, STM32 等等,同時提供 terminal 介面,真的很方便。

PlatformIO package
當然也支援conda 的環境。Anaconda 是一套提供python 及 環境的另一套介面程式,但我覺得跑起來有點慢,所以只使用了miniconda 的環境。另外也裝了intel 版的python,intel 的說法是,它針對 python 的AI 相關package 有做修正,執行速度更快(如Numpy, matlab, scimitar-learn 等)。
可以看到我的Python 是 intel 版的

要在Atom 內使用conda, 可以先安裝miniconda 後,再建立虛擬環境。
Intel 版的 python 可以在這裡找到,你可以裝單機版的,也可以裝 conda 版的,我是使用conda 版本,這裡有完整說明安裝方法。
在裝好conda 版的 intel python 虛擬環境後,再確認一下 hydrogen 的環境可不可正常work。
同樣可以在conda 的環境安裝ipython(互動式python)

conda create -n ipykernel_py2 python=2 ipykernel
source activate ipykernel_py2    # On Windows, remove the word 'source'
python -m ipykernel install --user
其中最後一行,是起動 ipykernel 的重要步驟,沒跑這行,你的 Atom 只會呼叫原始python 版本,不會使用你的ipython kernel 和 intel 版 python.

以上記錄,希望自己不會忘記~

2017年6月8日 星期四

Google Cloud Vision 學習筆記 2

安裝 Client library

這裡有介紹如何安裝你的語言版本的library

我用的是python,所以在command line 下:
pip install --upgrade google-cloud-vision

就會自動安裝了。

(2017/6/6) 等等,這個架構可以玩玩,但我是想要裝在RPi 上的,可是這個架構並沒有RPi 的 Google Cloud SDK. 只有for X86 linux, macOS 和 windows ⋯⋯ 
(2017/6/7) 找到一個 demo了,原來不一定要用Google Cloud SDK. 用API 就可以了。快來參考這篇。

安裝後,你會發現下面的範例是需要安裝 Google Cloud SDK,依照你的系統(我是用Mac),下載合適的SDK,再執行它的 install 檔。 然後 執行 gcloud init 來設定你的帳號和預設專案(project),若需要,可以再開一個 Google compute Engine API。依其範例,應該是用Google Compute Engine 來執行,因為後來我看 API 管理員的主頁,只有 Google Compute Engine API 有流量,Google Cloud Vision API 完全沒流量。
而且,請記得將SDK 安裝在~ 下,我之前放在 virtualenv 或其它目錄,執行gcloud 都會出現問題,搞了我好久。

安裝好 SDK 後,回到 Cloud Vision API Client Libraries 的說明,要再執行認證:
gcloud auth application-default login
這樣就差不多了。
然後 copy 以下檔案到你電腦裡的目錄:

C#

GO

JAVA

NODE.JS

PHP

PYTHON

RUBY

import ioimport os # Imports the Google Cloud client library from google.cloud import vision # Instantiates a client vision_client = vision.Client() # The name of the image file to annotate file_name = os.path.join(     os.path.dirname(__file__),     'resources/wakeupcat.jpg') # Loads the image into memory with io.open(file_name, 'rb') as image_file:     content = image_file.read()     image = vision_client.image(         content=content) # Performs label detection on the image file labels = image.detect_labels() print('Labels:') for label in labels:     print(label.description)
Read more in the Python API Reference Documentation for the Google Cloud Vision API Client Library.

其中 __file__ 會帶出你目前的檔案路徑,所以你的圖檔要放在你目前路徑下的 resources 目錄裡,至於圖檔名,就隨便你取。

再 執行此python 檔,就可以看到輸出的Json 結果。
基本上就是Google Vision 會判斷你的圖檔內容大概是什麼,可能性的機率有多高等等的。




2017年5月8日 星期一

Google Assistant 服務 在 RPi or Mac 上的應用

GooglePi

在網路上看到這篇文章,覺得很有興趣,Google Cloud 提供了$300 鎂 的免費試用,因此可以來試試。原本我還在學習圖型辨識,但我想最近AI 越來越強,自己也不是這領域的專家,與其重新學習去當巨人,不如直接站在巨人的肩頭上,看能不能當個巨人肩頭上的寄生蟲。
這裡有官方網頁的教學說明,更清楚:Overview

照著實作

第一步:啟動你的 RPi3

第二步:在Google Cloud 上設定 Google Assistant API

申請完 Google Clound後,首先新增一個專案
然後在Google Could Platform 上 選取 「API 管理員」裡的 「資訊主頁」
點選 在資訊主頁裡有項 「啟用API」


點選後,它會跳到 「API管理員」的 「資料庫」頁面,在搜尋欄裡,輸入「google assistant」,就可以看到 Google 自動幫你在它提供的100多個API 裡 filte 出來。 直接點選下面 filte 出來的 「Google Assistant API」
會看到頁面上針對 「Google Assistant API」的介紹與說明,然後點選頁面上的「啟用」
上面說明 「Google Assistant API」它使用的是 OAuth 2.0 的方式來存取使用者資料,因為它需要存取我們輸入給它的語音資料,因此需要授權。
點選 「OAuth 同意畫面」,如果沒有這個畫面,那先點選到「資料庫」,再點選「憑證」,應該就會有了。

點選「建立憑證」裡的 「OAuth 用戶端ID」
選擇「其它」,名稱用 google-assistant-rpi3, 或你自己取一個。
然後按 「建立」。

你應該就會得到下列畫面:
按下「確定」後,就可以看到你新建立的憑證。

然後點選右方的下載,將憑證存到你的電腦上。

至此,在google 的部分就設定完成了。

第三步:在RPi 上設定 Google Assistant(不過我是在Mac上設定)

首先設定 Python 的 虛擬環境。真的很神奇,現在連程式語言都提供虛擬環境讓你測試,避免像我這種初學者把環境弄得亂七八糟,搞不回來。虛擬環境搞亂了,就刪掉重來就好。

在mac 下,用home-brew 下載 portaudio 模組
然後啟用python虛擬環境,我用的是 virtualenv , 你可以看到 它會新建立一個叫 myenv 的環境:



之後就可以啟動我們的虛擬環境了⋯⋯

你會看到前面的提示符號多了一個 (myenv),即表示我們已經進入虛擬環境內。
接下來就可以安裝 Google Assistant SDK

切換到 ./myenv/bin 下,可以看到已經有兩個googlesamples 的 程式:

googlesamples-assistant 和 googlesamples-assistant-auth

同時把剛才的憑證一併copy 到這裡來
接下來,我們要用 googlesamples-assistant-auth 程式來先做憑證認證。

你會發現程式少了 google.auth 模組,再安裝 google.auth 模組:

再驗證一次憑證:
又少了 requests 模組,再來裝 requests 模組:
再驗證一次憑證:
還少了 google_auth_oauthlib 模組⋯⋯
再來裝 它 :
再驗證一次憑證:
還是少了 click 模組⋯⋯
再來裝它:

再驗證一次憑證:

你的browser 會跳出驗證的確認畫面:

點選你要啟用的帳號,然後再「同意」即完成認證。

Browser 畫面會變成:

同時  terminal 會回到提示符號。
差不多,我們就可以試試看,記得將你的RPi或電腦接上麥克風和喇叭。
然後執行 googlesamples-assistant:

唉⋯⋯還是少了 tenacity 模組,再來裝一下:
再來執行 googlesamples-assistant:
又少了 sounddevice 模組,相信我,這是最後一個我們缺的模組了⋯⋯

用力給它執行下去吧 googlesamples-assistant:

哈哈哈哈⋯⋯
終於可以囉~
這時,你只要按下 「enter」,然後對著Mic 說你要問的東西,Google Assistant 就會從喇叭回應囉⋯⋯可惜的是,它並不懂台語或中文。
至此己完全成功,如果你聽到它回應:
“Actually there are some basic settings that need your permission first. Just go into the Google Home app for details.”
那表示你的 google 帳號並沒有授權google 取用你的「聲音和語音活動」的權限,連到 Google Account Activity Controls 去啟動,就可以正常了。


謝謝參與。