作業函式的定義與呼叫

2022-02-03 02:45:09 字數 3985 閱讀 3457

作業函式的定義與呼叫

在 oneflow 中,將訓練、**任務封裝在乙個函式中,統稱為作業函式(job function),作業函式聯絡使用者的業務邏輯與 oneflow 管理的計算資源。

在 oneflow 中,被 @oneflow.global_function 裝飾器所修飾的 python 函式,就是 oneflow 作業函式。

主要在作業函式中定義網路模型的結構、選擇優化指標;此外,還可以將訓練有關的超參及環境配置當做引數,傳遞給作業函式(如:下面例子中的:get_train_config()),oneflow 會根據設定為管理記憶體、gpu 等硬體資源。

作業函式與 oneflow 執行流程的關係

作業函式分為定義和呼叫兩個階段。

這與 oneflow 本身的執行機制有關,簡化地說,oneflow python 層介面,只是在描述網路模型和訓練環境的配置資訊,這些資訊將傳遞給底層的 c++ **,經過編譯、優化等工作得到計算圖,最終交給 oneflow 執行時(runtime),由 oneflow 執行時執行。

因為定義作業函式只是做描述工作,在這個階段,並沒有實際的資料,而只能通過規定網路節點的形狀、資料型別等資訊,起到資料佔位符的作用,方便 oneflow 的編譯構圖過程進行模型推理。

作業函式的呼叫,發生在 oneflow runtime 已經啟動後,可以通過呼叫作業函式,向其傳遞真實的資料,並獲取返回結果。

以下將具體介紹作業函式的定義與呼叫方法。

作業函式的定義

將模型封裝在 python 中,再使用oneflow.global_function修飾符進行修飾。就完成了作業函式的定義。

作業函式主要描述兩方面的事情:

以下**示例中,構建了乙個 mlp 模型。並且將由 flow.nn.sparse_softmax_cross_entropy_with_logits 計算得到交叉熵損失結果作為優化目標。

@flow.global_function(type="train")

def train_job(

images: tp.numpy.placeholder((batch_size, 1, 28, 28), dtype=flow.float),

labels: tp.numpy.placeholder((batch_size,), dtype=flow.int32),

) -> tp.callback[tp.numpy]:

# mlp

initializer = flow.truncated_normal(0.1)

reshape = flow.reshape(images, [images.shape[0], -1])

hidden = flow.layers.dense(

reshape,

512,

activation=flow.nn.relu,

kernel_initializer=initializer,

name="hidden",

)logits = flow.layers.dense(

hidden, 10, kernel_initializer=initializer, name="output"

)loss = flow.nn.sparse_softmax_cross_entropy_with_logits(

labels, logits, name="softmax_loss"

)lr_scheduler = flow.optimizer.piecewiseconstantscheduler(, [0.1])

flow.optimizer.sgd(lr_scheduler, momentum=0).minimize(loss)

return loss

oneflow.global_function 的引數

oneflow.global_function 修飾符接受兩個引數,分別是 type 與 function_config。

def get_train_config():

config = flow.function_config()

config.default_data_type(flow.float)

return config

設定了預設資料型別,然後,可以在向 global_function 裝飾器傳遞這個function_config 物件:

@flow.global_function(type="train", function_config=get_train_config())

def train_job(

images: tp.numpy.placeholder((batch_size, 1, 28, 28), dtype=flow.float),

labels: tp.numpy.placeholder((batch_size,), dtype=flow.int32),

) -> tp.numpy:

包含以上**的完整示例可見文章consistent 與 mirrored 視角中的 mixed_parallel_mlp.py

資料佔位符

注意,以上的 images、logits、labels、loss等物件,在定義作業函式時,並沒有實際的資料。作用只是描述資料的形狀和屬性,起到佔位符的作用。

在作業函式的引數中的資料佔位符,使用 oneflow.typing 下的numpy.placeholder、listnumpy.placeholder、listlistnumpy.placeholder,註解作業函式的引數,對應作業函式呼叫時,傳遞 numpy 資料物件。

除了oneflow.typing下的幾種型別外,不出現在引數中,而由 oneflow 的運算元或層產生的變數,如以上**中的reshape、hidden、logits、loss等,也都起到了資料佔位符的作用。

不管是以上提及的哪種變數,都直接或間接繼承自 oneflow 的 blobdef 基類,oneflow 中把這種物件型別統稱為blob

blob在作業函式定義時,均無真實資料,均只起到資料佔位方便框架推理的作用。

作業函式的返回值

之所以在上文中強調資料佔位符blob的概念,因為作業函式的返回值是不能任意指定的,必須是 blob 型別的物件,或者存有 blob 物件的容器。

如以上**的中所返回的 loss,它就是 blob 型別。

作業函式的返回值,需要通過註解宣告,比如以上**中的 -> tp.numpy,表示返回1個 blob。

再比如,可以通過註解宣告返回值型別為 -> tuple[tp.numpy, tp.numpy],表示返回1個 tuple,該 tuple 中有2個 blob 物件。

具體的使用例子,可以參考獲取作業函式的結果

作業函式的呼叫

oneflow 利用函式修飾符將普通 python 函式轉變為 oneflow 特有的作業函式的過程,對於使用者而言是無感、透明的。

可以像呼叫普通的 python 函式一樣呼叫作業函式。每一次呼叫,oneflow 都會在框架內部完成正向傳播、反向傳播、引數更新等一系列事情。

以下**,獲取資料之後,向 train_job 作業函式傳遞引數並呼叫,列印 loss。

(train_images, train_labels), (test_images, test_labels) = flow.data.load_mnist(

batch_size

)for epoch in range(3):

for i, (images, labels) in enumerate(zip(train_images, train_labels)):

loss = train_job(images, labels)

if i % 20 == 0:

print(loss.mean())

可以看到,通過呼叫作業函式 train_job 直接返回了 numpy 資料。

以上展示的呼叫方式是同步方式, oneflow 還支援非同步呼叫,具體可以參閱專題獲取作業函式的結果。

函式的定義與呼叫

首先來了解一下概念 1.函式的定義 函式的定義就是對函式所要完的操作進行描述,即編寫一段程式,使該段程式完成函式所指定的操作。一般函式需要先定義後使用。沒有定義的函式不能使用。除主函式外的函式不能單獨執行,這些函式可以被主函式或其他函式呼叫,也可以條用其他函式,但不能呼叫主函式。2.函式的呼叫 程式...

C 函式的定義與呼叫

定義無參函式的一般形式 型別名 函式名 void 宣告部分 語句定義有參函式的一般形式 型別名 函式名 形式引數列表 宣告部分 語句寫兩個函式,分別要求兩個整數的最大公約數和最小公倍數,用主函式呼叫兩個函式,並輸出結果,兩個整數由鍵盤輸入。include stdafx.h include using...

3 1 函式的定義與呼叫

函式是c 程式的基本組成模組。通過函式,可以把乙個複雜任務分解成為若干個易於解決的小任務。充分體現結構化程式設計由粗到精,逐步細化的設計思想。什麼是函式 函式是c 程式的基本組成模組。組成c 程式的若干函式中,有乙個main winmain 函式,是程式執行的入口,它可以呼叫其他函式。而其他一般函式...