日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

gpxclear寄存器写0和写1_画图,搭积木,写对象 [TF 笔记 0]

發布時間:2023/12/15 编程问答 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 gpxclear寄存器写0和写1_画图,搭积木,写对象 [TF 笔记 0] 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

前言

從2019年9月底到現在,TF 2.0 已經正式發布三個多月了。但其實很多和 2.0 相關的特性,比如說 eager 模式,@tf.function 裝飾器和 AutoGraph, 以及 keras 風格的模型,在 TF 1.x 的后期版本中已經可以使用了。在過去的一年里,我和我們組的成員也一直在斷斷續續的把我們的代碼框架往 TF 2.x 的風格開始遷移。

回想我最早用 Tensorflow 是在2016年底,那時候 TF 1.0 還沒有正式登場。在那之前涉及到所有神經網絡的工作用的一直是 Caffe 和 MatConvNet, 更早一些是 Theano 。這三年來對 TF 的一個感受就是:模型訓練越來越快,部署越來越方便,但也實現起來也越來越復雜。雖然對于 TF 也有些迷思 (比如說很長一段時間里 TF 的卷積 (tf.nn.conv2d) 都不支持 Group Convolution,最后還是來自 FB 的研究人員提交的 PR,而且直到現在 TF 的文檔里也壓根沒提這事。。。),但整體來說我覺得它還是很好的一個框架。

我近幾年的工作主要是人臉檢測與識別,以及短視頻分析。用 TF 主要是來訓練卷積神經網絡,也涉及到一些 LSTM 的工作。我會試著從模型搭建,模型訓練,模型導出,分布式訓練以及如何寫自定義的層 (Layer) / 優化器 (Optimizer)/ 學習率 (Learing Rate Schedule) / 損失函數 Loss Function 等各個方面來看使用 TF 訓練卷積神經網絡的一路發展過來的變化。聊一聊在這個過程中踩過的一些坑,試著總結一下經驗。

題圖是去年參加 ICCV 時在會場旁邊拍的一個圖書館,與內容無關。

1. Tensorflow的模型有幾種寫法? 從畫圖,到搭積木,再到寫對象

1.1 計算圖

在最早期的 Tensorflow 里,寫模型的過程其實就是構造計算圖 (Computational Graph) 的過程。計算圖中的每一個節點 (Node) 定義了一個操作 (Operation),而計算圖中的邊 (Edge) 就是計算的數據 (Tensor) 。(嚴格來說還有另一種定義節點依賴關系 (Control Dependencies) 的邊,它們不承載數據,但是控制計算圖執行時節點的順序關系。)

圖1 計算圖示例

計算圖中的節點大致可以分為兩類,一類是數據節點,一類是計算節點。假設我們想要構建一個兩層的分類器,我們需要定義四個數據節點表示變量 [W1, b1, W2, b2],以及一個數據節點表示輸入數據 x,然后通過調用 tf.nn 下的各類計算節點來完成最后計算圖的構建,代碼如下所示:

def nn(x, num_classes):W1 = tf.Variable(tf.random_uniform([32, 64],-1,1), name='W1')b1 = tf.Variable(tf.zeros([64]), name='b1')W2 = tf.Variable(tf.random_uniform([64, num_classes],-1,1), name='W2')b2 = tf.Variable(tf.zeros([num_classes]), name='b2')dense_1 = tf.nn.relu(tf.matmul(x, W1) + b1)dense_2 = tf.nn.relu(tf.matmul(dense_1, W2) + b2)probs = tf.nn.softmax(dense_2)return probs x_tensor = tf.placeholder(tf.float32, shape=[None, 32], name='input') probs = nn(x_tensor, num_classes=10) TF 2.x (以及后期的 TF 1.x) 的一個重大的變化是 Variable 不再是一個與計算圖相關的全局變量, 而是與對象相關的一個局部變量。具體來說,在TF 1.x (早期的) 里,每當你新建一個 Variable 時,計算圖中會添加一個節點,我們可以通過 get_collection 的方法來收集圖中所有的 Variable。而在 TF2.x 里,每個 Variable是與創建它的對象相關的,對象可以是某個卷積層,也可以是某個模塊,也可以是整個模型。更多內容可以參考 TF community 的 RFC 文檔。

以上的代碼完成了計算圖的構建。TF 1.x 對于很多的操作提供一個更高層的 API tf.layers (TF 1.x 比較后期的版本需要訪問 tf.compat.v1.layers)。layers 封裝了計算和生成相關變量的過程,用 layers 來構建計算圖的代碼如下:

def nn(x, num_classes):dense1 = tf.compat.v1.layers.dense(x, 64, activation=tf.nn.relu, use_bias=True, name='fc1')dense2 = tf.compat.v1.layers.dense(dense1, num_classes, activation=tf.nn.relu, use_bias=True, name='fc2')probs = tf.nn.softmax(dense2)return probsx_tensor = tf.placeholder(tf.float32, shape=[None, 32], name='input') probs = nn(x_tensor, num_classes=10)

這種方法使用起來更方便,但本質和之前的方法是一樣的。

1.2 搭積木

關于 TF 2.0 的吐槽中,有一部分是關于 Keras 的。事實上從 TF 1.4 開始, Keras 就已經出現在了 TF 的 API 中。而且從 TF 1.9 開始,所有的 tf.layers 里的類,其實都是繼承自 Keras.layer 相對應的類。所以不管你喜歡不喜歡,只要你用了 tf.layers, 你就是在用 Keras 相關的設計 lol

用 Keras 搭建模型主要有兩種方式,分別是 Symbolic 式和 Imperative 式。(我實在不知道怎么翻譯這兩個詞。。。) 第一種就像是搭積木,第二種是直接寫一個 python 風格的對象 (pythonic) 。

搭積木的方法有兩種,第一種是序列化 (Sequential) 的方法。我們從輸入到輸出,將定義好的層一個個的連接起來,合并到一個 Sequential 的對象中去。

from tf.keras import layers model = tf.keras.Sequential([layers.Dense(64, activation='relu', input_shape=(32,), name='fc1'),layers.Dense(10, activation='relu', name='fc2'),layers.Activation(activation='softmax', name='sm')], name='nn')

這種方法有一個缺陷是對于每一層,我們只能使用一個輸入一個輸出,所以這種方法對于大部分的現代卷積神經網絡 (ResNet, DenseNet) 是沒有用的。TF 提供了另一種搭積木的方法,就是使用 Functional API。在 Functional API 下,我們不僅定義層,同時直接搭建出計算的過程。

from tf.keras import layers def get_model(num_classes):inputs = keras.Input(shape=(32,), name='input')x = layers.Dense(64, activation='relu')(inputs)x = layers.Dense(10, activation='relu')(x) outputs = layers.Activation(activation='softmax')(x)model = keras.Model(inputs=inputs, outputs=outputs, name='nn')return model

如果說 Sequential 的方式是在搭 Jenga, 那么 Function API 的方式更像是搭樂高,它更加的靈活,當我們需要使用多個輸入或者多個輸出的時候,只需要將將它們拼接起來即可,比如下面的這一個 Skip Connection 結構:

x1 = layers.Dense(64, activation='relu')(inputs)x2 = layers.Dense(64, activation='relu')(x1)x3 = x2 + x1

但是這兩種方法依然會有一些問題:

  • 訓練時和推理時的不一致: 現代卷積網絡中有些操作,比如說 BatchNormalization 還有 DropOut,它們在訓練和推理時是不一致的。但是從 DropOut 的 API 設置上大家可以看到,在它的接口里并沒有設置 是否訓練時 (training=True) 的地方。這個設置往往是在 Keras 后端設置的,所以這就限制了只能使用 Build-in 的訓練方法來訓練模型 ( model.fit() ) 或者需要很仔細的來手動控制訓練狀態。
  • 只能構建 DAG (Directed Acyclic Graph) 計算圖,不能有循環的部分。這個對于 RNN/LSTM 來說是一個致命的限制。
  • 1.3 最靈活的方法:Subclassing

    為了得到最大的靈活性,TF 提供一種面對對象的方式來構造模型。具體來說,我們繼承一 個 keras.model ,自己定義模型初始化以及前向傳播的過程 (后向傳播的過程會由 TF 自動生成)。以下是一個 Subclassing 的例子:

    from tf.keras import layersclass NN(tf.keras.Model):def __init__(self, units=64, num_classes=10):super(NN, self).__init__()self.units = unitsself.num_classes = num_classesself.dense1 = layers.Dense(self.units, activation='relu')self.dense2 = layers.Dense(self.num_classes, activation='relu')self.sm = layers.Activation(activation='softmax')def call(inputs, training=True):net = self.dense1(inputs)net = self.dense2(net) probs = self.sm(net)return probs

    在示例中我們可以看到,在 call 方法里我們有一個 argument 是 training (在這個例子中其實并沒有用,但是當我們使用 BN 還有 DropOut 時會非常有用),當調用模型時我們可以通過該參數來控制模型的運行模態:

    # model initialization nn = NN(units=64, num_classes=10)# training mode probs = nn(x, training=True) # testing mode probs = nn(x, training=False) Keras.Model 的具體實現:keras.Model 繼承于 keras.Network , keras.Network 繼承于 keras.Layer 。具體來說,Layer 定義了基本的運算單元,以及 Variable 的初始化過程;Network 定義了網絡的結構,這里的結構同時包含了前向傳播和后向傳播 (也就說 Optimizer 也包含在了 Network 里) 的網絡,同時 Network 中也定義了 Save 方法,也就是說當我們導出模型時其實是從 Network 這個層次發起的;Model 在 Network 的基礎上添加了訓練 (training),驗證 (evaluation) 以及測試 (testing) 的實現。

    雖然在 TF 中較晚才引入,但其實 Subclassing 并不是一個多新的概念,事實上在其它的框架中 (pyTroch, mxNet 等)很早有就了。 keras 的作者 Fran?ois Chollet 曾經發過這么一個推來比較不同框架下寫一個 RNN 的代碼,看上去是不是很像?

    圖2 不同框架 (TensorFlow, MXNet, Chainer, PyTorch) 下寫出的 RNN Image Credits: Fran?ois Chollet

    1.4 如何選擇

    以上就是我使用過的一些方法,但是在實際應用中,我們到底該如何選擇呢?我覺得這個問題并沒有一個固定的答案,它是由你的任務,你的預期以及生產環境決定的。

    • 如果你的模型和數據量都偏小,單卡訓練就可以,那么我覺得 Sequential 和 Function API 就足夠了;
    • 如果你模型和數據量都比較大,訓練時間對你來說最關鍵,需要多卡 MirroredStrategy 甚至用到 TPU,或者你有很多自定義的層,那么 Subclassing 會更靈活;
    • 如果部署問題對你來說是最關鍵的,后期需要做 TensorRT 或者 OpenVino 優化,那么用最底層的方式來寫模型可能會更合適。
    代碼風格變化的背后是底層框架的變化。TF1.x 的本質是構建和執行計算圖。但是從 TF1.x 的后期開始,TF 開始逐漸淡化用戶與計算圖的交互進而轉到用戶與對象圖 (ObjectGraph) 的交互。Layer / Model / Optimizer 等等對象,他們的基類都是一個 Trackable 類。TF2.x 的風格提倡我們從對象的層面來收集模型的損失項(losses,比如說正則項) 和更新項 (updates,比如說 BN 里的 Moving Average),以及控制梯度的更新。同時 TF2.x 倡導使用 @tf.function 裝飾器來編譯計算圖而不是使用 tf.session() 來執行計算圖。所有的這些,都是全局化風格向局部化風格的一個演進。

    ---------------------------------------------------------------------------------------

    下一篇會從模型訓練的角度來分析一下 TF 代碼風格的演變,主要會介紹和分析一下 TF 是如何從自定義訓練 (Session-based Custom Training), 到 Estimator,再到 Build-in 訓練,最后又回到自定義訓練 (GradientTape-based Custom Training) 的。

    參考文獻:

  • TensorFlow: Large-Scale Machine Learning on Heterogeneous Distributed Systems
  • What are Symbolic and Imperative APIs in TensorFlow 2.0?
  • Inside Tensorflow 來自 TF team 內部的分享,非常值得一看
  • TensorFlow Offical Document
  • 總結

    以上是生活随笔為你收集整理的gpxclear寄存器写0和写1_画图,搭积木,写对象 [TF 笔记 0]的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。