三分鍾快速上手TensorFlow 2.0 再學習總結回顧


https://www.bilibili.com/video/av89601743

嗶哩嗶哩上面有一位道友專門針對《簡單粗暴》分享了他的個人經驗,我也跟着復習了一遍,挑一些重點的記錄一下

這是一個工程師的角度,從開發的角度理解t f的構建

 

其實求梯度、導數、斜率都差不多的概念 然后是求他們的損失函數,我們的目標就是減少損失函數

tf里面主要就是張量的運算,costant和varieble

 with。。。as。。其實相當於一個記錄器,之后就可以直接用這個記錄器里面的內容

對於線性的來說,x和y是已經知道的部分,求的是w和b(也可能是多個w),也可以說是分別對做w、b偏導

w、b是損失函數中的未知數

 reduce_sum就是求和

 歸一化還是比較有用滴,但是最后一定要記得返歸一化

權重偏置一般一開始是隨機給予或者為0 

梯度下降要慢慢來,也就是學習率的大小不能過大,但是也不能太小

 zip(grads,variable)就是將[a_grad,b_grad]和[a,b]配對,[(a_grad,a),(b_grad,b)]

optimizer的作用就是a= a-a*a_grad*learning_rate,b也同理

我們不是求y_pred=a*X+b的最小值,而是求loss=0.5*tf.reduce_sum(tf.square(y_pred-y))最優化,所以損失函數一定要放在tape里面

 

真正神經網絡函數肯定不是一維的,所以會是y = w1*x1+w2*x2+w3*x3+b等

下圖是對於損失函數求偏導的過程 (視頻中講解時把2忽略了不做考慮,但博主認為並沒有消去,所以最后結算的時候應該是和學習率相乘了)

super().__init__()的作用是定義基類(雞肋🤣)

class :

  def init:

  def call:

    在這里不單單是一層的結果作為下一層的輸入,也可以是不同的值輸入到不同的層里面,得到的輸出再輸入到同一個層里面(比如有一個很淺的層,然后有一個很深的層,兩個結果結合到一個層以后這樣子泛化能力會比較強)

    output

自后就會用這個output去做損失的計算和梯度計算

 

y_pred = w1*x1+w2*x2+w3*x3+b

這里給一個多元的訓練樣本,x=tf.constant( [[1,2,3],[4,5,6]])那這里其實就是相當於是放入了三個元(1,4)(2,5)(3,6)

units= 1 神經元的個數

activition激活函數   kernel_initializer權重系數    bias_initializer偏置系數

 

optimizer對權重系數和偏執做梯度下降

 

tape記錄用來求y_pred和loss

grads計算tape.gradient(loss,model.variable)  model.variable直接獲得所有變量,也就是[[w1,w2,w3],b]

optimizer.apply_gradient(grads_and_vars=zip(grads,model.variable))  綁定grad和相對應變量交給優化器

以上三個loss、grads、optimizer不斷循環epoch

 

偏置向量bias,即b是默認有的

 

batch的作用就是批次下取平均值,比較有助於避免一些奇異的離異點,避免得到離群樣本的干擾

 flattern的作用就是打平,類似於將一張皺巴巴的紙鋪展開來(28,28,1)變成(784,)

也就是相當於y=w1x1+w2x2+...+W783x783+b  kernel = [w1,w2,w3...w783],bias=b

 

softmax(x)的作用就是將x個元素分布在[0,1]之間(歸一化),求導是一組概率,所有元素最后的和為1.通俗的講就是x屬於某一類的概率分別是多少

 

num_batches = int(data_loader.num_train//batch_ssize*num_epochs)總的訓練數除以訓練批次再乘以訓練次數,前面相當於按照批大小把大蛋糕分成了好幾份,后一個則是說重復吃這個蛋糕epochs次

for....in range(num_batches):

  x,y=每次取batchsize大小的蛋糕(所以循環的總次數=蛋糕的塊數*迭代次數)

  with ...as tape:

    y_pred = model(x)

    loss=交叉熵得到的損失函數(batchsize個元素)

    loss=tf.reduce_mean(loss) 樣本的平均損失函數,計算出來的值只有一個浮點數

  grads= 

  optimizer=

交叉熵就是將y_pred[0.1,0.5,0.,0.,0.,...] 和 y_real[0,1,0,0,0,0,...]計算得出一個總的概率,分布越接近則得到的浮點數越小,在正常的計算中,得到的應為batchsize個概率「」

可以看到每一次循環中僅得到一個loss的浮點數,然后計算梯度,再用優化器優化

 

metric模型評估也可以批量地進行

sparse_前綴的意義就是允許我們傳入標量5——》[0,0,0,0,1,0,0,0,..]

 

 

CNN= 卷積層+池化層+全聯接層

eg.input->卷+卷+池+池+平+全+全->output

卷積層相當於用一個方框掃描這一個層(filters卷積層神經元樹木【聚集核,可以理解為一共有多少個窗口/kernel去滑動,每次完成后會對這幾個窗口的結果求平均值】、kernel_size=[n,n]感受野大小、 padding='same'給最后的輸出的部分補0,讓輸出的大小和輸入的保持一致),用一個窗口滑動,每次滑動之后對於窗口內計算的各個元素求和再加上偏置項

tf.squeeze(output)     

tf.squeeze(input, squeeze_dims=None, name=None)從tensor中刪除所有大小是1的維度,如果不想刪除所有尺寸1尺寸,可以通過指定squeeze_dims來刪除特定尺寸1尺寸。

strides參數(默認1)用於設置步長

 

池化層 也是滑動,可以理解為降采樣,對之前卷積結束以后得到的新的層,再用窗口滑動取其中的最大值,[14,14]的圖經過大小[2,2]的池化(四個里面選一個最大的)后變成[7,7]

 

[28,28,1]  其中1代表灰度圖像,只有一層,[   [[],[],[]..28個,[],[]]    ,[....],[...],.28組..]

[28,28,3]  其中3代表3個通道,[   [[a,b,c],[a,b,c],[a,b,c]..28個,[],[]]    ,[....],[...],.28組..]

三個數里面最后一個你可以理解為圖層的概念,所以也是會變的,主要是看你在選擇卷積層的時候核(filter)選了多大的

 

 

RNN

訓練

i am a stud->t

i have a boyf->r

...

預測(每一次輸入的大小要一樣)

we have a boy->f

e have a boyf->r

  have a boyfr->i(注意這里為保證數量大小,最前面必有一個空格)

 

 

class...:

  def init:

      讀取文本,大寫改為小寫

      去重還加了排序

      給每一個內容標注下標

      內容和下標反正標注了一下(與上面一行一起用就可以很方便地在單詞和編號之間互換查找了)

      對於原文,利用上面的編碼標注,將其轉化成編號形式的數字列表

   def ...(self,seq_length,batch_size):

      seq = []

      next_char=[]

      for i in range(batch_size):

        index = np.random.randint(0,len(self.text)-seq_length)隨機選一個編號

 

        seq.append(self.text[index:index+seq_length])將這個編號和它后面 滑動窗口大小 個組合成一個list元素

        next_char.append(self.text[index+seq_length])加入上一行代碼取到的數列之后的那個數據

      return np.array(seq),np.array(next_char)            類型是[batch_size,seq_length],[batch_size]

 

 

onehot獨熱

[45,7,1]->46會轉化為很多0 和一個1的模式

[[0,0,0,0,0,.....1,0,0,0,...,0]  [0,0,0,0,0,0,1,0,...,0] [0,1,0,0,...]]->[0,0,0,0,0,...1,0,0,0,0,...]

 

class RNN(tf.keras.Model): def __init__(self, num_chars總共有多少種不同的字符, batch_size, seq_length): super().__init__() self.num_chars = num_chars(onehot編碼的長度) self.seq_length = seq_length self.batch_size = batch_size self.cell = tf.keras.layers.LSTMCell(units=256) self.dense = tf.keras.layers.Dense(units=self.num_chars)(這里一定是onehot的長度) def call(self, inputs, from_logits=False): inputs = tf.one_hot(inputs, depth=self.num_chars) # [batch_size, seq_length, num_chars] state = self.cell.get_initial_state(batch_size=self.batch_size, dtype=tf.float32) 【給設置的神經元設置一個初始化的狀態】 for t in range(self.seq_length): output, state = self.cell(inputs[:, t, :]【所有的大list里面的所有小list,第t個list,這個list所有的值,也就是相當於最小的那個list單元里的所有元素(即獨熱的那個)】, state) 這里的output可以理解為已經預測了,也就是它認為下一個應該是什么 logits = self.dense(output) if from_logits: return logits 原樣輸出 else: return tf.nn.softmax(logits) 輸出對應的概率

對於batch_size應該理解為將這個蛋糕切成多少份,而不是每一份蛋糕的大小?
在RNN環境下直接用model.predict()效果不會很好(默認其實是調用call方法),會找最大的那個值,因此重新定義

 def predict(self, inputs, temperature=1.): batch_size, _ = tf.shape(inputs) logits = self(inputs, from_logits=True) prob = tf.nn.softmax(logits / temperature).numpy() return np.array([np.random.choice(self.num_chars, p=prob[i, :]) for i in range(batch_size.numpy())])

之前用tf.argmax()取最大的作為預測值,對於文本生成太過於絕對,因此使用np.random.choice()函數按照生成的概率分布取樣(這樣概率小的也可能被取到)

同時加入temperature參數控制發布大小參數越大分布越平緩(最大、小值的差值於誒奧,生成的文本越豐富)

 X_, _ = data_loader.get_batch(seq_length, 1) for diversity in [0.2, 0.5, 1.0, 1.2]: diversity(也就是predict里面傳進去的temperature)給的比較小的時候就生成的比較死板,越大越豐富 X = X_ print("diversity %f:" % diversity) for t in range(400):              往后面再生成400個字 y_pred = model.predict(X, diversity) print(data_loader.indices_char[y_pred[0]], end='', flush=True) 還記得一開始定義的那個字和編號組隊的字典嗎,對,現在用上面一行給出的數字去找對應的字 X = np.concatenate([X[:, 1:]【這里1:很妙,相當於拋去第一個字,然后后面再連接新的字】, np.expand_dims(y_pred, axis=1)]【連上我們新預測的那個字】, axis=-1) print("\n")

np.expand_dims:用於擴展數組的形狀

np.argmax:返回沿軸最大值的索引值

 

DRL強化學習部分暫缺

 

 

 

###############

接下來的方法和上面的構建模型的方法有所不同,比如模型需要compile和fit

###############

 

Keras 的 Sequential API通過向 tf.keras.models.Sequential() 提供一個層的列表,由 Keras 將它們自動首尾相連

model = tf.keras.models.Sequential([ tf.keras.layers.Flatten(), tf.keras.layers.Dense(100, activation=tf.nn.relu), tf.keras.layers.Dense(10), tf.keras.layers.Softmax() ])

Keras 提供 Functional API 多輸入 / 輸出或存在參數共享的模型。將層作為可調用的對象並返回張量

        inputs = tf.keras.Input(shape=(28, 28, 1)) x = tf.keras.layers.Flatten()(inputs) x = tf.keras.layers.Dense(units=100, activation=tf.nn.relu)(x) x = tf.keras.layers.Dense(units=10)(x) outputs = tf.keras.layers.Softmax()(x) model = tf.keras.Model(inputs=inputs, outputs=outputs)



compile 方法配置訓練過程:

model.compile( optimizer=tf.keras.optimizers.Adam(learning_rate=0.001), loss=tf.keras.losses.sparse_categorical_crossentropy, metrics=[tf.keras.metrics.sparse_categorical_accuracy] ) 

fit 方法訓練模型

model.fit(data_loader.train_data【訓練數據】, data_loader.train_label【目標數據(數據標簽)】, epochs=num_epochs, batch_size=batch_size)【應該還可以加一個validation_data :驗證數據,可用於在訓練過程中監控模型的性能】

evaluate 評估訓練效果

print(model.evaluate(data_loader.test_data, data_loader.test_label))





所以歸納一下構建模型的方法

1.繼承類的keras.Model,call()定義任意的復雜的網絡結構

2.keras.Model 傳入任意個inputs和outputs定義任意的復雜的網絡結構

3..keras.Model.Sequential,只能定義簡單的一層傳一層的方式

 

 

自定義層 繼承 tf.keras.layers.Layer 類,並重寫 __init__ 、 build 和 call 三個方法

class MyLayer(tf.keras.layers.Layer): def __init__(self): super().__init__() # 初始化代碼 def build(self, input_shape): # input_shape 是一個 TensorShape 類型對象,提供輸入的形狀 # 在第一次使用該層的時候調用該部分代碼,在這里創建變量可以使得變量的形狀自適應輸入的形狀 # 而不需要使用者額外指定變量形狀。 # 如果已經可以完全確定變量的形狀,也可以在__init__部分創建變量 self.variable_0 = self.add_weight(...) self.variable_1 = self.add_weight(...) def call(self, inputs): # 模型調用的代碼(處理輸入並返回輸出) return output

比如這里先自定義一個層

class LinearLayer(tf.keras.layers.Layer): def __init__(self, units): super().__init__() self.units = units def build(self, input_shape): # 這里 input_shape 是第一次運行call()時參數inputs的形狀 self.w = self.add_variable(name='w',【一定要用add的方式而不能直接variable】 shape=[input_shape[-1]【取到最里面那一層】, self.units], initializer=tf.zeros_initializer())【建議改成隨機的賦值,tf.random_normal_initializer()】
self.b = self.add_variable(name='b', shape=[self.units], initializer=tf.zeros_initializer())【建議改成隨機的賦值,tf.random_normal_initializer()】 def call(self, inputs): y_pred = tf.matmul(inputs, self.w) + self.b return y_pred

再自定義一個模型調用上面的層

class LinearModel(tf.keras.Model): def __init__(self): super().__init__() self.layer = LinearLayer(units=1) def call(self, inputs): output = self.layer(inputs) return output


自定義損失函數,【可以在compile里面修改loss這一塊】class MeanSquaredError(tf.keras.losses.Loss):

 def call(self, y_true, y_pred):
    【在這里面因為原來的數據中y_ture和y_pred的結果格式不一樣所以下面這一行對格式做了onehot處理】
    y_true = tf.squeeze(y_true,axis = -1)【因為keras在自定義的時候會自己升維,所以這里加上這一行代碼用來降維處理,把最里面的一個list剝除】
    y_true = tf.one_hot(tf,cast(y_true,dtype='int32),depth = 10)
    
return tf.reduce_mean(tf.square{tf.reduce_sum(y_pred - y_true)))【這里加一個reduce_sum就是未來保證開方里面只有一個值】
 

自定義評估指標【可以在compile里面修改metric這一塊】【自定義的時候有時候結果會升高維度(即每個元素會自己套上一個list)】

class SparseCategoricalAccuracy(tf.keras.metrics.Metric): def __init__(self): super().__init__() self.total = self.add_weight(name='total', dtype=tf.int32, initializer=tf.zeros_initializer()) self.count = self.add_weight(name='count', dtype=tf.int32, initializer=tf.zeros_initializer()) def update_state(self, y_true, y_pred, sample_weight=None):
     y_true = tf.squeeze(y_true,axis = -1)【因為keras在自定義的時候會自己升維,所以這里加上這一行代碼用來降維處理,把最里面的一個list剝除】 values = tf.cast【類型轉化】(tf.equal【返回true/false】(y_true, tf.argmax【返回概率最大的那個下標】(y_pred, axis=-1, output_type=tf.int32)), tf.int32) self.total.assign_add(tf.shape(y_true)[0])【實際上就是batch_size】 self.count.assign_add(tf.reduce_sum(values))【每一次答對的次數】 def result(self): return self.count / self.total

 

使用tf.config.experimental_run_functions_eagerly(True)之后可以在代碼運行計算中print你想要的,否則是不會實時計算的,他會自己進入優化

 

變量的保存與恢復

tf.train.Checkpoint 這一強大的變量保存與恢復類

聲明

checkpoint = tf.train.Checkpoint(model=model) 

或者自己命名checkpoint = tf.train.Checkpoint(myAwesomeModel=model, myAwesomeOptimizer=optimizer)
 
          

保存

checkpoint.save(保存文件的目錄 + 前綴)

重新載入

model_to_be_restored = MyModel() # 待恢復參數的同一模型 checkpoint = tf.train.Checkpoint(myAwesomeModel=model_to_be_restored) # 鍵名保持為“myAwesomeModel” checkpoint.restore(之前保存的文件的目錄 + 前綴 + 編號save_path_with_prefix_and_index)


總結:
# train.py 模型訓練階段

model = MyModel() # 實例化Checkpoint,指定保存對象為model(如果需要保存Optimizer的參數也可加入) checkpoint = tf.train.Checkpoint(myModel=model) # ...(模型訓練代碼) # 模型訓練完畢后將參數保存到文件(也可以在模型訓練過程中每隔一段時間就保存一次) checkpoint.save('./save/model.ckpt')


# test.py 模型使用階段

model = MyModel() checkpoint = tf.train.Checkpoint(myModel=model) # 實例化Checkpoint,指定恢復對象為model checkpoint.restore(tf.train.latest_checkpoint('./save')) # 從文件恢復模型參數 # 模型使用代碼

 

 

只想保留最后的幾個 Checkpoint;

checkpoint = tf.train.Checkpoint(model=model) manager = tf.train.CheckpointManager(checkpoint, directory='./save', checkpoint_name='model.ckpt', max_to_keep=k) 

自行指定保存的 Checkpoint 的編號,則可以在保存時加入 checkpoint_number 參數。例如 manager.save(checkpoint_number=100)

 

TensorBoard:類似於一種埋點保存

定義

summary_writer = tf.summary.create_file_writer('./tensorboard') # 參數為記錄文件所保存的目錄

記錄器(不只是scalar)

with summary_writer.as_default(): # 希望使用的記錄器 tf.summary.scalar("loss", loss, step=batch_index) tf.summary.scalar("MyScalar", my_scalar, step=batch_index) # 還可以添加其他自定義的變量 

終端運行,【使用瀏覽器訪問命令行程序所輸出的網址(一般是 http:// 計算機名稱:6006)】【如果要監聽所有端口就在后面打賞--bind_all】

tensorboard --logdir=./tensorboard

Graph看結構Profile看耗時

tf.summary.trace_on(graph=True, profiler=True) # 開啟Trace,可以記錄圖結構和profile信息 #########
# 進行訓練的代碼
######### with summary_writer.as_default(): tf.summary.trace_export(name="model_trace", step=0, profiler_outdir=log_dir) # 保存Trace信息到文件【建議將
log_dir改為./tensorboard這樣子就不會單獨放到另外的文件夾里面了

【一些坑:1、每一次訓練用這個記得把之前的記錄的刪掉!!!!!2、trace_on直接放在大的循環里面會持續地占有大內存,事實上只要記錄一次就行了,采用個位數的batch意思意思就能出圖了3、自定義的層之間沒有圖的聯系,或者說是不是強連接,所以在def call()上面加上@tf.function這樣會自動編程圖的結構,這個是即時模式Eager Execution的弊端,當然,如果是用pipeline/sequential的那種因為有compile那一步就會保存為圖來執行了

 

@tf.function 修飾符,將模型以圖執行模式運行。【在原有的函數外圍再包一層函數】【函數參數只包括 TensorFlow 張量或 NumPy 數組】【相當於再翻譯一遍代碼】【會事先先運行一遍代碼,之后運行都會執行翻譯后的代碼,但是如果傳入的參數類型轉變了,那它就會再一次執行原來的代碼再翻譯一遍】

使用TensorFlow內置的tf.print()。@tf.function不支持Python內置的print方法

 

t f.data

dataset = tf.data.Dataset.from_tensor_slices((X, Y))#X輸入Y輸出

mnist_dataset = tf.data.Dataset.from_tensor_slices((train_data, train_label))

dataset = dataset.map(函數)

mnist_dataset = mnist_dataset.batch(4)划分批次

mnist_dataset = mnist_dataset.shuffle(buffer_size=10000).batch(4)數據打散后再設置批次,緩存大小設置為 10000:

mnist_dataset = mnist_dataset.prefetch(buffer_size=tf.data.experimental.AUTOTUNE)開啟預加載數據

mnist_dataset = mnist_dataset.map(map_func=函數, num_parallel_calls=【CPU個數】)利用多核心的優勢對數據進行並行化變換

數據集元素的獲取與使用

dataset = tf.data.Dataset.from_tensor_slices((A, B, C, ...)) for a, b, c, ... in dataset: # 對張量a, b, c等進行操作,例如送入模型進行訓練

it = iter(dataset) a_0, b_0, c_0, ... = next(it) a_1, b_1, c_1, ... = next(it)#使用 iter() 顯式創建一個 Python 迭代器並使用 next() 獲取下一個元素
model.fit(mnist_dataset, epochs=num_epochs)#使用 tf.data.Dataset 后,我們可以直接傳入 Dataset 

 

 

多輸入和多特征的概念

多輸入是多組特征,進入不同的inputs,(比如k 線圖特征和開盤價特征兩種數據集一個進入CNN一個進入RNN,最后輸出到一個全聯接層?) 

 

 

TFRecord數據集存儲格式(不吃內存,數據在內存里面了)

整理為 TFRecord 格式 

  • 讀取到內存;

  • 轉換為 tf.train.Example 對象(每一個  由若干個 tf.train.Feature 的字典組成,需要先建立 Feature 的字典);

  • 將該 對象序列化為字符串,並通過一個預先定義的 tf.io.TFRecordWriter 寫入 TFRecord 文件。

with tf.io.TFRecordWriter(tfrecord_file) as writer: for filename, label in zip(train_filenames, train_labels): image = open(filename, 'rb').read() # 讀取數據集圖片到內存,image 為一個 Byte 類型的字符串 feature = { # 建立 tf.train.Feature 字典 'image': tf.train.Feature(bytes_list=tf.train.BytesList(value=[image])), # 圖片是一個 Bytes 對象 'label': tf.train.Feature(int64_list=tf.train.Int64List(value=[label])) # 標簽是一個 Int 對象 } example = tf.train.Example(features=tf.train.Features(feature=feature)) # 通過字典建立 Example writer.write(example.SerializeToString()) # 將Example序列化並寫入 TFRecord 文件

讀取 TFRecord 數據

  • 通過 tf.data.TFRecordDataset 讀入原始的 TFRecord 文件(此時文件中的 tf.train.Example 對象尚未被反序列化),獲得一個 tf.data.Dataset 數據集對象;
  • 通過 Dataset.map 方法,對該數據集對象中的每一個序列化的 tf.train.Example 字符串執行 tf.io.parse_single_example 函數,從而實現反序列化
raw_dataset = tf.data.TFRecordDataset(tfrecord_file) # 讀取 TFRecord 文件 feature_description = { # 定義Feature結構,告訴解碼器每個Feature的類型是什么 'image': tf.io.FixedLenFeature([], tf.string), 'label': tf.io.FixedLenFeature([], tf.int64), } def _parse_example(example_string): # 將 TFRecord 文件中的每一個序列化的 tf.train.Example 解碼 feature_dict = tf.io.parse_single_example(example_string, feature_description) feature_dict['image'] = tf.io.decode_jpeg(feature_dict['image']) # 解碼JPEG圖片 return feature_dict['image'], feature_dict['label'] dataset = raw_dataset.map(_parse_example)

 

tf.TensorArray

時間序列的結構中,我們可能需要將一系列張量以數組的方式依次存放起來,以供進一步處理。

在即時執行模式下,你可以直接使用一個 Python 列表(List)存放數組。不過,如果你需要基於計算圖的特性(例如使用 @tf.function 加速模型運行或者使用 SavedModel 導出模型),就無法使用這種方式了

import tensorflow as tf @tf.function def array_write_and_read(): arr = tf.TensorArray(dtype=tf.float32, size=3) #聲明一個大小為 size ,類型為 dtype 的 TensorArray arr 。如果將 dynamic_size 參數設置為 True ,則該數組會自動增長空間。 arr = arr.write(0, tf.constant(0.0))#寫入 arr = arr.write(1, tf.constant(1.0)) arr = arr.write(2, tf.constant(2.0)) arr_0 = arr.read(0)#讀取 arr_1 = arr.read(1) arr_2 = arr.read(2) return arr_0, arr_1, arr_2 a, b, c = array_write_and_read() print(a, b, c)

還包括 stack() 、 unstack() 等常用操作

 

tf.config

gpus = tf.config.experimental.list_physical_devices(device_type='GPU') cpus = tf.config.experimental.list_physical_devices(device_type='CPU') print(gpus, cpus)
gpus = tf.config.experimental.list_physical_devices(device_type='GPU') tf.config.experimental.set_visible_devices(devices=gpus[0:2], device_type='GPU')#只使用下標為 0、1 的兩塊顯卡
import os os.environ['CUDA_VISIBLE_DEVICES'] = "2,3"即可指定程序只在顯卡 2,3 上運行。



gpus = tf.config.experimental.list_physical_devices(device_type='GPU') tf.config.experimental.set_virtual_device_configuration( gpus[0], [tf.config.experimental.VirtualDeviceConfiguration(memory_limit=1024)])#建立了一個顯存大小為 1GB 的 “虛擬 GPU”
 

 

gpus = tf.config.experimental.list_physical_devices('GPU') tf.config.experimental.set_virtual_device_configuration( gpus[0], [tf.config.experimental.VirtualDeviceConfiguration(memory_limit=2048), tf.config.experimental.VirtualDeviceConfiguration(memory_limit=2048)])#在實體 GPU GPU:0 的基礎上建立了兩個顯存均為 2GB 的虛擬 GPU。

 

 導出為 SavedModel 文件時,無需建立模型的源代碼即可再次運行模型,適用於模型的分享和部署。后文的 TensorFlow Serving(服務器端部署模型)、TensorFlow Lite(移動端部署模型)以及 TensorFlow.js 都會用到這一格式。

  

 

tf.saved_model.save(model, "保存的目標文件夾名稱") #導出

model = tf.saved_model.load("保存的目標文件夾名稱")  #載入

 

注意⚠️

繼承 tf.keras.Model 類建立的 Keras 模型,其需要導出到 SavedModel 格式的方法(比如 call )都需要使用 @tf.function 修飾

對於使用繼承 tf.keras.Model 類建立的 Keras 模型 model ,使用 SavedModel 載入后將無法使用 model() 直接進行推斷,而需要使用 model.call() 。 

 

——————————分割————

Sequential 下的保存和ke ra s的保存不太一樣,自己帶了save的格式

model.save('mnist_cnn.h5') #保存模型
在服務器端,可以直接通過 keras.models.load_model("mnist_cnn.h5") #加載模型
然后進行推理;在移動設備需要將 HDF5 模型文件轉換為 TensorFlow Lite 的格式,然后通過相應平台的 Interpreter 加載,然后進行推理。
這個時候model后面帶不帶call都是可以的

 

 

TensorFlow Serving部署模型

Keras Sequential mode直接用命令

tensorflow_model_server \
    --rest_api_port=8501 \ --model_name=MLP \ --model_base_path="/home/.../.../saved" # 文件夾絕對地址根據自身情況填寫,無需加入版本號 

Custom Keras models

不僅需要使用 @tf.function 修飾,還要在修飾時指定 input_signature 參數

@tf.function(input_signature=[tf.TensorSpec([None, 28, 28, 1], tf.float32)])      

#輸入是一個 [None, 28, 28, 1] 的四維張量( None 表示第一維即 Batch Size 的大小不固定)

 

tf.saved_model.save(model, "saved_with_signature/1", signatures={"call": model.call})  #在調用模型時使用 call 這一簽名來調用 model.call 方法時,我們可以在導出時傳入 signature 參數,以 dict 的鍵值對形式告知導出的方法對應的簽名

而后可以使用命令

tensorflow_model_server \
    --rest_api_port=8501 \ --model_name=MLP \ --model_base_path="/home/.../.../saved_with_signature" # 修改為自己模型的絕對地址

 

在客戶端調用以 TensorFlow Serving 部署的模型

在客戶端向服務器發送以下格式的請求:

服務器 URI: http://服務器地址:端口號/v1/models/模型名:predict

請求內容:

{
    "signature_name": "需要調用的函數簽名(Sequential模式不需要)", "instances": 輸入數據 } 

回復為:

{
    "predictions": 返回值 }
import json
import numpy as np
import requests
from zh.model.utils import MNISTLoader


data_loader = MNISTLoader()
data = json.dumps({
    "instances": data_loader.test_data[0:3].tolist()
    })
headers = {"content-type": "application/json"}
json_response = requests.post(
    'http://localhost:8501/v1/models/MLP:predict',
    data=data, headers=headers)
predictions = np.array(json.loads(json_response.text)['predictions'])
print(np.argmax(predictions, axis=-1))
print(data_loader.test_label[0:10])
python的格式調用

jason 只認python的數組,所以要用.tolist()的方法

⚠️調用ke ra s自定義的模型時不要忘記了傳

"signature_name": "call",

【返回的json可以在bejason.com這個網站上面查看】

 

tensorflow sever 可以穿一個model_config_file的文件同時運行多個模型

 

拓展:

多輸入,兩路輸入,最后合到一個輸入。再一開始定義的時候那個@tf.function(input_signature=[tf.TensorSpec([None28281],name='a',dtype=tf.float32),tf.TensorSpec([None28281],name='b',detype=tf.float32)])  

后面requests的時候不能用instance去post,而是要改為"inputs":{'a':[1,2,3],'b':[4,5,6]}【a b相當於特征的名字】,請求返回的是outputs的Jason

 

 

 

 

 

 

 對於視頻中還存在一些我感覺不是很明白的地方,如果有大佬知道請多指正!

Q:p6那里的783、784之間少了一個1不是很懂

 

Q:tf.squeeze(input, squeeze_dims=None, name=None)從tensor中刪除所有大小是1的維度,如果不想刪除所有尺寸1尺寸,可以通過指定squeeze_dims來刪除特定尺寸1尺寸。
p9里面池化層取【2,2】的大小是取最大值,那要是取大一點的窗口也是取最大值嗎?


Q:
p11
07:51這里cha r s不僅僅是去重還將大寫改為小寫,還加了排序
11:48這里我覺得應該是【從0開始 到 倒數seq_length】里面選取一個編號?


Q:
p12
9:13是否能理解為【所有的大list里面的所有小list,第t個list,這個list所有的值,也就是相當於最小的那個list單元里的所有元素(即獨熱的那個)】什么時候from_logits可以為true?


Q:
p13
對於batch_size應該理解為將這個蛋糕切成多少份,而不是每一份蛋糕的大小?
12:32 temperature = 1.時候為什么除一下以后會壓扁?
19:35 np.expand_dims:用於擴展數組的形狀

 

Q:
p16
6:37為什么都要用到tf.cast來轉換類型,直接用int()的方法不行嗎?

 

Q:
p20
7:56 @tf.function 會執行一遍代碼,如果在運行的代碼里面有print也會輸出,那這時候的那個數據在總的運行次數里面有加入到訓練當中嗎

A:只是跑一次生成計算圖代碼,忽略輸出,然后再重新開始跑計算吧。

 

Q:
p22
6:39多輸入和多特征的概念
多輸入是多組特征,進入不同的inputs,(比如k 線圖特征和開盤價特征兩種數據集一個進入CNN一個進入RNN,最后輸出到一個全聯接層?)
1.這個時候在構建模型的時候是不是sequential的那種構建方式不能用了,而model和自定義里面可以?
2.多特征應該怎么樣呢將(x,y)變成(x,y,z)?fit的時候如何判斷哪個是輸入的x1x2x3哪個是輸出y1y2呢
3.那是不是((A,B),(C),(D))這樣是不可能的
10:23 from_tenor_slices((輸入,輸出)),多輸入的情況是from_tenor_slices((輸入,輸入,輸入,輸出))嗎?還是還需要嵌套一層元組

 

Q:
p24 write(index, value) :將 value 寫入數組的第 index 個位置;
6:06 對於時間序列的數據,是不是寫的時候就是
arr = tf.TensorArray(dtype=tf.float32, size=3)【這個size是代表arr里面放幾種編號嗎】
arr = arr.write(1, tf.variable(x))【這里x假設是代表着日期,那前面只要寫1就行了還是說要用循環把1替換成1~日期總數?】
10:56 如果只有CPU的情況下,應該采取怎么樣的優化方式

Q:
p25
15:28 input里面(none,28,28,1)none是batch的個數,什么時候是必須要加上的呢,batch不是在fit里面設定的嗎?

A:自定義的ke ra s需要部署到serving上時;

 

Q:

p26
10:36
一個模型如果我有多組特征
1合並放在一個輸入層里面
2分開放在不同輸入層里面
如果輸入層的配置相同的情況下,效果也是相同的嗎?(感覺應該如果各特征沒有相關性的話效果相同)

 

Q:

 
p28
11:37 講得是模型的多輸入的
對於多特征來說要是想輸入到一個層里面怎么做呢,現在網上關於tf2的都是輸入一個特征的,很少輸入多個特征的,講得也不清晰。那我同一個數據集里面的多個特征只能按照多輸入的方式每一個單獨弄一套最后划到同一層上面嗎

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM