1. 程式人生 > >學習筆記:caffe2 教程記錄五

學習筆記:caffe2 教程記錄五

接著caffe2 教程記錄四,這個是第五篇

##5.Brewing Models 

brew是Caffe2用於構建模型的新API。 CNNModelHelper過去曾擔任過這個角色,但由於Caffe2的擴充套件遠遠超出了CNN的優勢,因此提供更通用的ModelHelper物件是有意義的。 您可能會注意到新的ModelHelper與CNNModelHelper具有許多相同的功能。 brew包裝了新的ModelHelper,使得建築模型比以前更容易。

模型構建和brew Helper 函式

在本概述中,我們將介紹brew,一個輕量級的輔助函式集合,可幫助您構建模型。 我們將首先解釋Ops與Helper函式的關鍵概念。 然後我們將展示brew 用法,以及它如何充當ModelHelper物件的介面,以及arg_scope語法糖。 最後,我們討論了引入brew的動機。

概念:Ops與Helper函式

在我們深入研究brew之前,我們應該回顧一下Caffe2中的一些約定以及神經網路的層是如何表示的。 Caffe2中的深度學習網路由operators 構建。 通常,這些運算子是用C ++編寫的,以獲得最佳效能。 Caffe2還提供了一個包裝這些C ++運算子的Python API,因此您可以更靈活地進行實驗和原型。 在Caffe2中,運算子總是以CamelCase方式呈現,而具有類似名稱的Python輔助函式以小寫形式呈現。 這樣的例子如下。

Ops

我們經常將運算子稱為“Op”或運算子集合作為“Ops”。 例如,FC Op代表一個完全連線的運算子,該運算子與前一層中的每個神經元和下一層的每個神經元都有加權連線。 例如,您可以使用以下命令建立FC Op:

model.net.FC([blob_in, weights, bias], blob_out)

或者您可以建立一個Copy Op:

model.net.Copy(blob_in, blob_out)

 

ModelHelper處理的運算子列表位於本文件的底部。 目前包括最常用的29個Ops。 這是Caffe2在撰寫本文時所擁有的400+ Ops的一部分。 

還應注意,您還可以建立一個沒有註釋網路的Operator。 例如,就像我們建立Copy Op的前一個示例一樣,我們可以使用以下程式碼在model.net上建立一個Copy運算子(操作符):

model.Copy(blob_in, blob_out)

 Helper 函式:

僅僅使用單個操作員來構建模型/網路可能很費勁,因為您必須自己完成引數初始化,裝置/引擎選擇(但這也是Caffe2如此之快的原因!)。 例如,要構建一個FC層,您需要使用幾行程式碼來準備權重和偏差,然後將其提供給Op。

這是傳統的畫時間比較多的,手動建立方式:

model = model_helper.ModelHelper(name="train")
# initialize your weight
weight = model.param_init_net.XavierFill(
    [],
    blob_out + '_w',
    shape=[dim_out, dim_in],
    **kwargs, # maybe indicating weight should be on GPU here
)
# initialize your bias
bias = model.param_init_net.ConstantFill(
    [],
    blob_out + '_b',
    shape=[dim_out, ],
    **kwargs,
)
# finally building FC
model.net.FC([blob_in, weights, bias], blob_out, **kwargs)

幸運的是,Caffe2輔助函式可以提供幫助。 輔助函式是包裝函式,可為模型建立完整的圖層。 輔助函式通常用於處理引數初始化,操作符定義和引擎選擇。 Caffe2預設Helper函式在Python PEP8函式約定中命名。 例如,使用python / helpers / fc.py,通過輔助函式fc實現FC Op要簡單得多:

使用輔助函式簡單的建立方法:

fcLayer = fc(model, blob_in, blob_out, **kwargs) # returns a blob reference

一些helper函式會構建超過1個operator。 例如,python/rnn_cell.py 中的LSTM函式可幫助您在網路中構建整個LSTM單元。 

檢視更多的helper 函式,可點選 repo ,你會看到下面的helper函式。

 

brew

現在你已經瞭解了Ops和Helper功能,讓我們來介紹一下brew如何使模型構建變得更加容易。 brew是一個智慧的輔助函式集合。 只需匯入一個brew模組,即可使用所有Caffe2強大的幫助程式功能。 您現在可以使用以下方法新增FC圖層:

from caffe2.python import brew

brew.fc(model, blob_in, blob_out, ...)

這與直接使用輔助函式幾乎相同,但是一旦模型變得更復雜,brew就會開始發揮它的強大作用了。 以下是從MNIST教程中提取的LeNet模型構建示例。

from caffe2.python import brew

def AddLeNetModel(model, data):
    conv1 = brew.conv(model, data, 'conv1', 1, 20, 5)
    pool1 = brew.max_pool(model, conv1, 'pool1', kernel=2, stride=2)
    conv2 = brew.conv(model, pool1, 'conv2', 20, 50, 5)
    pool2 = brew.max_pool(model, conv2, 'pool2', kernel=2, stride=2)
    fc3 = brew.fc(model, pool2, 'fc3', 50 * 4 * 4, 500)
    fc3 = brew.relu(model, fc3, fc3)
    pred = brew.fc(model, fc3, 'pred', 500, 10)
    softmax = brew.softmax(model, pred, 'softmax')

每個層都是使用brew建立的,而brew又使用其操作符hooks來例項化每個Op。 

arg_scope :

arg_scope是一種語法糖,可以在其上下文中設定預設的輔助函式引數值。 例如,假設您想在ResNet-150訓練指令碼中嘗試不同的權重初始化。 你可以:

# change all weight_init here
brew.conv(model, ..., weight_init=('XavierFill', {}),...)
...
# repeat 150 times
...
brew.conv(model, ..., weight_init=('XavierFill', {}),...)

或者在arg_scope的幫助下,你可以

with brew.arg_scope([brew.conv], weight_init=('XavierFill', {})):
     brew.conv(model, ...) # no weight_init needed here!
     brew.conv(model, ...)
     ...

自定義Helper 函式:

當您更頻繁地使用brew並且發現需要實現Brew目前不涵蓋的Op時,您將需要編寫自己的helper函式。 您可以將您的helper 函式註冊為brew,以享受統一管理和語法糖。
只需定義新的helper函式,使用.Register函式將其註冊到brew,然後使用brew.new_helper_function呼叫它。
 

def my_super_layer(model, blob_in, blob_out, **kwargs):
"""
   100x faster, awesome code that you'll share one day.
"""

brew.Register(my_super_layer)
brew.my_super_layer(model, blob_in, blob_out)

如果您認為您的helper函式可能對Caffe2社群的其他成員有幫助,請記住共享它,並建立一個pull請求。

Caffe2 預設的 Helper 函式:

要獲取有關每個功能的更多詳細資訊,請訪問操作員目錄(Operators Catalogue.)。

 使用 brew的動機:

感謝您閱讀有關brew的全部概述!恭喜你,你終於來了!簡而言之,我們希望將模型構建過程和模型儲存分開。在我們看來,ModelHelper類應該只包含網路定義和引數資訊。 brew模組將具有構建網路和初始化引數的功能。
與之前同時進行模型儲存和模型構建的巨型CNNModelHelper相比,模型構建的ModelHelper + brew方式更加模組化,更易於擴充套件。在命名方面,由於Caffe2系列支援各種網路,包括MLP,RNN和CNN,因此它也更不容易混淆。我們希望本教程能夠幫助您更快,更輕鬆地建立模型,同時更深入地瞭解Caffe2。
python/brew_test.py 中有一個brew使用的詳細示例。如果您對brew有任何疑問,請隨時與我們聯絡,並在回購問題中提出問題。再次感謝您擁抱新的brew API。

##6.Regression - Plotting Lines & Random Data

https://github.com/caffe2/tutorials/blob/master/Toy_Regression.ipynb

這是一個快速示例,展示瞭如何使用caff2的基礎知識中的概念進行迴歸。 本教程分為兩部分。 第一部分是建立和訓練多項式迴歸模型的更詳細的例子,第二部分是一個簡潔的線性迴歸例子。

第一部分:多項式迴歸
我們正在處理的問題是一個相對簡單的問題,涉及一維輸入x 和一維輸出 y。因為我們尋找二階多項式作為迴歸模型,權重向量將包含兩個權重(beta_2 和 beta_1)並且會有一個偏差(beta_0 )或攔截。 所需的解決方案形式如下:

                                                    $$y = \beta_2x^2 + \beta_1x + \beta_0$$

在本教程中,我們將生成並格式化具有強二階多項式關係的任意輸入資料集。 然後我們將構建模型,指定訓練演算法,執行訓練,最後檢視結果。

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
from caffe2.python import workspace, brew, optimizer
from caffe2.python.model_helper import ModelHelper
import numpy as np
%matplotlib inline
import matplotlib.pyplot as plt
import sklearn.datasets
from sklearn.preprocessing import PolynomialFeatures

在此指定迴歸模型的輸入引數包括:輸入資料中的樣本數,訓練迭代次數,SGD演算法的學習率以及模型的初始權重


# Number of training sample to generate# Numbe 
num_samples = 200
# Learning Rate of SGD algorithm
learning_rate = .05
# Number of iterations to train
training_iters = 100
# Initial model weights
initial_weights = [0.,0.]

建立並準備資料集
現在,我們將建立並準備用於模型的資料集。 注意,我們只是在這裡構建numpy陣列。 可以使用任何其他資料,只要它在輸入到模型之前被正確地整形。

# Create the original observations
orig_X,_ = sklearn.datasets.make_regression(n_samples=num_samples,n_features=1,noise=5)
poly = PolynomialFeatures(degree=2, include_bias=False)
# Transform the features into second order polynomial features
xx_ = poly.fit_transform(orig_X)

# Extract the predictors and the values from the manufactured data
X = [i[0] for i in xx_]
Y_gt = [i[1] for i in xx_]
noise = np.random.uniform(size=(len(Y_gt)))
# Add some noise to the ground truth values
Y_gt += noise

# Shape the ground truth values for use with the model
Y_gt = np.reshape(Y_gt,(-1,1))
# Format the input features. Recall, we accomplish polynomial regression by
#   including the original and the polynomial version of the predictors
#   as features of the model
X = np.hstack((np.array(X).reshape(-1,1),np.array(X).reshape(-1,1)**2))

# Print a sample of the input data. X is the list of 2-feature input observations 
#   and Y is the list of ground truth values associated with each observation
print("X Sample:\n{}".format(X[:5]))
print("Y Sample:\n{}".format(Y_gt[:5]))

# Plot the input data
plt.scatter([i[0] for i in X],Y_gt,label="original data",color='b')
plt.xlabel("x")
plt.ylabel("y")
plt.title("Input Training Data")

下面是執行出來的結果:

建立模型
定義模型體系結構
通過建立我們的訓練資料和我們的二階多項式假設,我們現在可以建立一個模型來學習迴歸線。我們將使用“FC”層作為模型的主要元件。由於我們需要兩個權重( beta_2 和 beta_1),我們將輸入維度設定為2,並且由於我們只期望單個定量結果,所以我們的輸出維度為1,注意,當使用“FC”圖層時暗示存在偏差,我們將使用它作為 beta_0。

此外,在繼續檢視此步驟中建立的protobuf之前。第一個列印輸出是'net',包含模型的體系結構。乍看之下,我們看到正如預期的那樣,網路中有一個操作符需要輸入X,權重和偏差,並輸出 y_pred,在打印出'param_init_net'時我們看到這是權重和偏差的初始化存在的地方。這是一個重要的觀察結果,可以深入瞭解如何構建和維護Caffe2中的模型。

# Create the model helper object we will use to create the regression model
regression_model = ModelHelper(name="regression_model")

# Add the FC layer, which is the main component of a linear regression model
y_pred = brew.fc(regression_model,'X','y_pred', dim_in=2, dim_out=1)

# Print the predict and init net to see what protobuf was created for this model
print("************* Predict Net *************")
print(regression_model.net.Proto())
print("\n************* Init Net *************")
print(regression_model.param_init_net.Proto())

執行出來的結果:

新增train operators 並填充到 workspace 工作空間
在這個非常重要的步驟中,我們指定損失函式,設定SGD訓練演算法,初始化和初始化工作空間,並初始化模型的權重和偏差。

# The loss function is computed by a squared L2 distance, 
#   and then averaged over all items.
dist = regression_model.SquaredL2Distance(['Y_gt', y_pred], "dist")
loss = regression_model.AveragedLoss(dist, "loss")

# Add the gradient operators and setup the SGD algorithm
regression_model.AddGradientOperators([loss])
optimizer.build_sgd(regression_model, base_learning_rate=learning_rate)

# Prime the workspace with some data
workspace.FeedBlob("Y_gt",Y_gt.astype(np.float32))
workspace.FeedBlob("X",X.astype(np.float32))

# Run the init net to prepare the workspace then create the net
workspace.RunNetOnce(regression_model.param_init_net)
workspace.CreateNet(regression_model.net)

# Inject our desired initial weights and bias
workspace.FeedBlob("y_pred_w",np.array([initial_weights]).astype(np.float32))
workspace.FeedBlob("y_pred_b",np.array([0.]).astype(np.float32))

執行訓練:

# Run the training for training_iters
for i in range(training_iters):
    workspace.RunNet(regression_model.net)

print("Training Complete")

提取結果
現在我們的模型已經過訓練,我們可以提取在名為“y_pred_w”和“y_pred_b”的工作空間中作為blob存在的學習權重和偏差。

# Extract the learned coes and intercept from the workspace
coes = workspace.FetchBlob("y_pred_w")[0]
intercept = workspace.FetchBlob("y_pred_b")

# Calculate the regression line for plotting
x_vals = np.linspace(orig_X.min(), orig_X.max(),100)
regression_result = intercept[0] + coes[0]*x_vals + coes[1]*(x_vals**2)
print("Best Fit Line: {}*x^2 + {}*x + {}".format(round(coes[1],5), round(coes[0],5), round(intercept[0],5)))

# Plot the results of the regression
plt.scatter([i[0] for i in X],Y_gt,label="original data",color='b')
plt.plot(x_vals,regression_result,label="regression result",color='r')
plt.legend()
plt.xlabel("x")
plt.ylabel("y")
plt.title("Polynomial Regression Fit: ${{{}}}x^2 + {{{}}}x + {{{}}}$".format(round(coes[1],5), round(coes[0],5), round(intercept[0],5)))
plt.show()

執行出來的結果:

第二部分:快速線性迴歸示列

上面的示例顯示瞭如何建立一個易於調整以處理高階多項式的多項式迴歸模型。 現在,我們將考慮基線情況,我們需要一個簡單的一階模型,一維輸入x,1-D輸出 y,已經表單的解決方案:

                                                                                          $$y = \beta_1x + \beta_0$$

第二部分的結構與第一部分類似。首先,我們將生成資料集,然後我們將構建模型並指定訓練例程,最後我們將訓練和提取我們的結果。

#####################################################################
# Initialize data
#####################################################################
X,Y_gt = sklearn.datasets.make_regression(n_samples=100,n_features=1,noise=10)
Y_gt = np.reshape(Y_gt,(-1,1))
Y_gt /= 100.

#####################################################################
# Create and train model
#####################################################################
# Construct model with single FC layer
regression_model = ModelHelper(name="regression_model")
y_pred = brew.fc(regression_model,'X','y_pred', dim_in=1, dim_out=1)

# Specify Loss function
dist = regression_model.SquaredL2Distance(['Y_gt', y_pred], "dist")
loss = regression_model.AveragedLoss(dist, "loss")

# Get gradients for all the computations above.
regression_model.AddGradientOperators([loss])
optimizer.build_sgd(regression_model, base_learning_rate=0.05)

# Prime and prepare workspace for training
workspace.FeedBlob("Y_gt",Y_gt.astype(np.float32))
workspace.FeedBlob("X",X.astype(np.float32))
workspace.RunNetOnce(regression_model.param_init_net)
workspace.CreateNet(regression_model.net)

# Set the initial weight and bias to 0
workspace.FeedBlob("y_pred_w",np.array([[0.]]).astype(np.float32))
workspace.FeedBlob("y_pred_b",np.array([0.]).astype(np.float32))

# Train the model
for i in range(100):
    workspace.RunNet(regression_model.net)

#####################################################################
# Collect and format results
#####################################################################
# Grab the learned weight and bias from workspace
coe = workspace.FetchBlob("y_pred_w")[0]
intercept = workspace.FetchBlob("y_pred_b")

# Calculate the regression line for plotting
x_vals = range(-3,4)
regression_result = x_vals*coe + intercept

# Plot the results
plt.scatter(X,Y_gt,label="original data",color='b')
plt.plot(x_vals,regression_result,label="regression result",color='r')
plt.legend()
plt.xlabel("x")
plt.ylabel("y")
plt.title("Regression Line: ${{{}}}x + {{{}}}$".format(round(coe,5), round(intercept[0],5)))
plt.show()

執行出來的結果: