timertask run函數未執行_圖執行模式下的 TensorFlow 2

文 /??李錫涵,Google Developers Expert

本文節選自《簡單粗暴 TensorFlow 2.0》

b9e66442b62f865bb84db1de50fc8396.png

盡管 TensorFlow 2 建議以即時執行模式(Eager Execution)作為主要執行模式,然而,圖執行模式(Graph Execution)作為 TensorFlow 2 之前的主要執行模式,依舊對于我們理解 TensorFlow 具有重要意義。尤其是當我們需要使用 tf.function 時,對圖執行模式的理解更是不可或缺。

圖執行模式在 TensorFlow 1.X 和 2.X 版本中的 API 不同:
  • 在 TensorFlow 1.X 中,圖執行模式主要通過 “直接構建計算圖 +?tf.Session” 進行操作;
  • 在 TensorFlow 2 中,圖執行模式主要通過?tf.function?進行操作。

在本章,我們將在 tf.function:圖執行模式?一節的基礎上,進一步對圖執行模式的這兩種 API 進行對比說明,以幫助已熟悉 TensorFlow 1.X 的用戶過渡到 TensorFlow 2。

提示
TensorFlow 2 依然支持 TensorFlow 1.X 的 API。為了在 TensorFlow 2 中使用 TensorFlow 1.X 的 API ,我們可以使用?import tensorflow.compat.v1 as tf?導入 TensorFlow,并通過?tf.disable_eager_execution()?禁用默認的即時執行模式。

TensorFlow 1+1

TensorFlow 的圖執行模式是一個符號式的(基于計算圖的)計算框架。簡而言之,如果你需要進行一系列計算,則需要依次進行如下兩步:
  • 建立一個 “計算圖”,這個圖描述了如何將輸入數據通過一系列計算而得到輸出;
  • 建立一個會話,并在會話中與計算圖進行交互,即向計算圖傳入計算所需的數據,并從計算圖中獲取結果。

使用計算圖進行基本運算?

這里以計算 1+1 作為 Hello World 的示例。以下代碼通過 TensorFlow 1.X 的圖執行模式 API 計算 1+1:

import tensorflow.compat.v1 as tf
tf.disable_eager_execution()

# 以下三行定義了一個簡單的“計算圖”
a = tf.constant(1) # 定義一個常量張量(Tensor)
b = tf.constant(1)
c = a + b # 等價于 c = tf.add(a, b),c是張量a和張量b通過 tf.add 這一操作(Operation)所形成的新張量
# 到此為止,計算圖定義完畢,然而程序還沒有進行任何實質計算。
# 如果此時直接輸出張量 c 的值,是無法獲得 c = 2 的結果的

sess = tf.Session() # 實例化一個會話(Session)
c_ = sess.run(c) # 通過會話的 run() 方法對計算圖里的節點(張量)進行實際的計算
print(c_)
輸出:
2
而在 TensorFlow 2 中,我們將計算圖的建立步驟封裝在一個函數中,并使用?@tf.function修飾符對函數進行修飾。當需要運行此計算圖時,只需調用修飾后的函數即可。由此,我們可以將以上代碼改寫如下:
import tensorflow as tf# 以下被 @tf.function 修飾的函數定義了一個計算圖@tf.functiondef graph():
a = tf.constant(1)
b = tf.constant(1)
c = a + breturn c# 到此為止,計算圖定義完畢。由于 graph() 是一個函數,在其被調用之前,程序是不會進行任何實質計算的。# 只有調用函數,才能通過函數返回值,獲得 c = 2 的結果
c_ = graph()
print(c_.numpy())

小結

  • 在 TensorFlow 1.X 的 API 中,我們直接在主程序中建立計算圖。而在 TensorFlow 2 中,計算圖的建立需要被封裝在一個被 @tf.function 修飾的函數中;

  • 在 TensorFlow 1.X 的 API 中,我們通過實例化一個 tf.Session ,并使用其 run 方法執行計算圖的實際運算。而在 TensorFlow 2 中,我們通過直接調用被 @tf.function 修飾的函數來執行實際運算。

計算圖中的占位符與數據輸入?

上面這個程序只能計算 1+1,以下代碼通過 TensorFlow 1.X 的圖執行模式 API 中的 tf.placeholder() (占位符張量)和 sess.run()feed_dict 參數,展示了如何使用 TensorFlow 計算任意兩個數的和:

import tensorflow.compat.v1 as tf
tf.disable_eager_execution()

a = tf.placeholder(dtype=tf.int32) # 定義一個占位符Tensor
b = tf.placeholder(dtype=tf.int32)
c = a + b

a_ = int(input("a = ")) # 從終端讀入一個整數并放入變量a_
b_ = int(input("b = "))

sess = tf.Session()
c_ = sess.run(c, feed_dict={a: a_, b: b_}) # feed_dict參數傳入為了計算c所需要的張量的值
print("a + b = %d" % c_)

運行程序:

>>> a = 2
>>> b = 3
a + b = 5

而在 TensorFlow 2 中,我們可以通過為函數指定參數來實現與占位符張量相同的功能。為了在計算圖運行時送入占位符數據,只需在調用被修飾后的函數時,將數據作為參數傳入即可。由此,我們可以將以上代碼改寫如下:

import tensorflow as tf

@tf.function
def graph(a, b):
c = a + b
return c

a_ = int(input("a = "))
b_ = int(input("b = "))
c_ = graph(a_, b_)
print("a + b = %d" % c_)

小結在 TensorFlow 1.X 的 API 中,我們使用 tf.placeholder() 在計算圖中聲明占位符張量,并通過 sess.run()feed_dict 參數向計算圖中的占位符傳入實際數據。而在 TensorFlow 2 中,我們使用 tf.function 的函數參數作為占位符張量,通過向被 @tf.function 修飾的函數傳遞參數,來為計算圖中的占位符張量提供實際數據。

計算圖中的變量?

變量的聲明?

(Variable)是一種特殊類型的張量,使用 tf.get_variable()建立,與編程語言中的變量很相似。使用變量前需要先初始化,變量內存儲的值可以在計算圖的計算過程中被修改。以下示例代碼展示了如何建立一個變量,將其值初始化為 0,并逐次累加 1。
import tensorflow.compat.v1 as tf
tf.disable_eager_execution()

a = tf.get_variable(name='a', shape=[])
initializer = tf.assign(a, 0.0) # tf.assign(x, y)返回一個“將張量y的值賦給變量x”的操作
plus_one_op = tf.assign(a, a + 1.0)

sess = tf.Session()
sess.run(initializer)
for i in range(5):
sess.run(plus_one_op) # 對變量a執行加一操作
print(sess.run(a)) # 輸出此時變量a在當前會話的計算圖中的值
輸出:
1.0
2.0
3.0
4.0
5.0

提示為了初始化變量,也可以在聲明變量時指定初始化器(initializer),并通過 tf.global_variables_initializer() 一次性初始化所有變量,在實際工程中更常用:

import tensorflow.compat.v1 as tf
tf.disable_eager_execution()

a = tf.get_variable(name='a', shape=[],
initializer=tf.zeros_initializer) # 指定初始化器為全0初始化
plus_one_op = tf.assign(a, a + 1.0)

sess = tf.Session()
sess.run(tf.global_variables_initializer()) # 初始化所有變量
for i in range(5):
sess.run(plus_one_op)
print(sess.run(a)
在 TensorFlow 2 中,我們通過實例化tf.Variable類來聲明變量。由此,我們可以將以上代碼改寫如下:
import tensorflow as tf

a = tf.Variable(0.0)

@tf.function
def plus_one_op():
a.assign(a + 1.0)
return a

for i in range(5):
plus_one_op()
print(a.numpy())

小結
在 TensorFlow 1.X 的 API 中,我們使用 tf.get_variable() 在計算圖中聲明變量節點。而在 TensorFlow 2 中,我們直接通過 tf.Variable 實例化變量對象,并在計算圖中使用這一變量對象。

變量的作用域與重用?在 TensorFlow 1.X 中,我們建立模型時經常需要指定變量的作用域,以及復用變量。此時,TensorFlow 1.X 的圖執行模式 API 為我們提供了 tf.variable_scope()reuse 參數來實現變量作用域和復用變量的功能。以下的例子使用了 TensorFlow 1.X 的圖執行模式 API 建立了一個三層的全連接神經網絡,其中第三層復用了第二層的變量。
import tensorflow.compat.v1 as tf
import numpy as np
tf.disable_eager_execution()

def dense(inputs, num_units):
weight = tf.get_variable(name='weight', shape=[inputs.shape[1], num_units])
bias = tf.get_variable(name='bias', shape=[num_units])
return tf.nn.relu(tf.matmul(inputs, weight) + bias)

def model(inputs):
with tf.variable_scope('dense1'): # 限定變量的作用域為 dense1
x = dense(inputs, 10) # 聲明了 dense1/weight 和 dense1/bias 兩個變量
with tf.variable_scope('dense2'): # 限定變量的作用域為 dense2
x = dense(x, 10) # 聲明了 dense2/weight 和 dense2/bias 兩個變量
with tf.variable_scope('dense2', reuse=True): # 第三層復用第二層的變量
x = dense(x, 10)
return x

inputs = tf.placeholder(shape=[10, 32], dtype=tf.float32)
outputs = model(inputs)
print(tf.global_variables()) # 輸出當前計算圖中的所有變量節點
sess = tf.Session()
sess.run(tf.global_variables_initializer())
outputs_ = sess.run(outputs, feed_dict={inputs: np.random.rand(10, 32)})
print(outputs_)
在上例中,計算圖的所有變量節點為:
['dense1/weight:0' shape=(32, 10) dtype=float32>,'dense1/bias:0' shape=(10,) dtype=float32>,'dense2/weight:0' shape=(10, 10) dtype=float32>,'dense2/bias:0' shape=(10,) dtype=float32>]

可見,tf.variable_scope() 為在其上下文中的,以 tf.get_variable 建立的變量的名稱添加了 “前綴” 或 “作用域”,使得變量在計算圖中的層次結構更為清晰,不同 “作用域” 下的同名變量各司其職,不會沖突。同時,雖然我們在上例中調用了 3 次 dense 函數,即調用了 6 次 tf.get_variable 函數,但實際建立的變量節點只有 4 個。這即是 tf.variable_scope()reuse 參數所起到的作用。當 reuse=True 時, tf.get_variable 遇到重名變量時將會自動獲取先前建立的同名變量,而不會新建變量,從而達到了變量重用的目的。

而在 TensorFlow 2 的圖執行模式 API 中,不再鼓勵使用 tf.variable_scope() ,而應當使用 tf.keras.layers.Layertf.keras.Model 來封裝代碼和指定作用域,具體可參考 本手冊第三章。上面的例子與下面基于 tf.kerastf.function 的代碼等價。
import tensorflow as tf
import numpy as np

class Dense(tf.keras.layers.Layer):
def __init__(self, num_units, **kwargs):
super().__init__(**kwargs)
self.num_units = num_units

def build(self, input_shape):
self.weight = self.add_variable(name='weight', shape=[input_shape[-1], self.num_units])
self.bias = self.add_variable(name='bias', shape=[self.num_units])

def call(self, inputs):
y_pred = tf.matmul(inputs, self.weight) + self.bias
return y_pred

class Model(tf.keras.Model):
def __init__(self):
super().__init__()
self.dense1 = Dense(num_units=10, name='dense1')
self.dense2 = Dense(num_units=10, name='dense2')

@tf.function
def call(self, inputs):
x = self.dense1(inputs)
x = self.dense2(inputs)
x = self.dense2(inputs)
return x

model = Model()
print(model(np.random.rand(10, 32)))

我們可以注意到,在 TensorFlow 2 中,變量的作用域以及復用變量的問題自然地淡化了。基于 Python 類的模型建立方式自然地為變量指定了作用域,而變量的重用也可以通過簡單地多次調用同一個層來實現。

為了詳細了解上面的代碼對變量作用域的處理方式,我們使用 get_concrete_function導出計算圖,并輸出計算圖中的所有變量節點:
graph = model.call.get_concrete_function(np.random.rand(10, 32))
print(graph.variables)
輸出如下:
('dense1/weight:0' shape=(32, 10) dtype=float32, numpy=...>,'dense1/bias:0' shape=(10,) dtype=float32, numpy=...>,'dense2/weight:0' shape=(32, 10) dtype=float32, numpy=...>,'dense2/bias:0' shape=(10,) dtype=float32, numpy=...)
可見,TensorFlow 2 的圖執行模式在變量的作用域上與 TensorFlow 1.X 實際保持了一致。我們通過name參數為每個層指定的名稱將成為層內變量的作用域。

小結
在 TensorFlow 1.X 的 API 中,使用 tf.variable_scope()reuse 參數來實現變量作用域和復用變量的功能。在 TensorFlow 2 中,使用 tf.keras.layers.Layertf.keras.Model 來封裝代碼和指定作用域,從而使變量的作用域以及復用變量的問題自然淡化。兩者的實質是一樣的。

自動求導機制與優化器?

在本節中,我們對 TensorFlow 1.X 和 TensorFlow 2 在圖執行模式下的自動求導機制進行較深入的比較說明。

自動求導機制?我們首先回顧 TensorFlow 1.X 中的自動求導機制。在 TensorFlow 1.X 的圖執行模式 API 中,可以使用 tf.gradients(y, x) 計算計算圖中的張量節點 y 相對于變量 x 的導數。以下示例展示了在 TensorFlow 1.X 的圖執行模式 API 中計算e23e8c8b55289a0c1d3b40eb1005da08.png1655f326c8e18aee5a5d04b875361f3a.png時的導數。
x = tf.get_variable('x', dtype=tf.float32, shape=[], initializer=tf.constant_initializer(3.))
y = tf.square(x) # y = x ^ 2
y_grad = tf.gradients(y, x)

以上代碼中,計算圖中的節點 y_grad 即為 y 相對于 x 的導數。

而在 TensorFlow 2 的圖執行模式 API 中,我們使用 tf.GradientTape 這一上下文管理器封裝需要求導的計算步驟,并使用其 gradient 方法求導,代碼示例如下:

x = tf.Variable(3.)
@tf.function
def grad():
with tf.GradientTape() as tape:
y = tf.square(x)
y_grad = tape.gradient(y, x)
return y_grad

小結
在 TensorFlow 1.X 中,我們使用 tf.gradients() 求導。而在 TensorFlow 2 中,我們使用使用 tf.GradientTape 這一上下文管理器封裝需要求導的計算步驟,并使用其 gradient 方法求導。

優化器

由于機器學習中的求導往往伴隨著優化,所以 TensorFlow 中更常用的是優化器(Optimizer)。在 TensorFlow 1.X 的圖執行模式 API 中,我們往往使用tf.train中的各種優化器,將求導和調整變量值的步驟合二為一。例如,以下代碼片段在計算圖構建過程中,使用 tf.train.GradientDescentOptimizer這一梯度下降優化器優化損失函數 loss

y_pred = model(data_placeholder)    # 模型構建
loss = ... # 計算模型的損失函數 loss
optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.001)
train_one_step = optimizer.minimize(loss)
# 上面一步也可拆分為
# grad = optimizer.compute_gradients(loss)
# train_one_step = optimizer.apply_gradients(grad)

以上代碼中, train_one_step 即為一個將求導和變量值更新合二為一的計算圖節點(操作),也就是訓練過程中的 “一步”。特別需要注意的是,對于優化器的 minimize 方法而言,只需要指定待優化的損失函數張量節點 loss 即可,求導的變量可以自動從計算圖中獲得(即 tf.trainable_variables )。在計算圖構建完成后,只需啟動會話,使用 sess.run 方法運行 train_one_step 這一計算圖節點,并通過 feed_dict 參數送入訓練數據,即可完成一步訓練。代碼片段如下:

for data in dataset:
data_dict = ... # 將訓練所需數據放入字典 data 內
sess.run(train_one_step, feed_dict=data_dict)

而在 TensorFlow 2 的 API 中,無論是圖執行模式還是即時執行模式,均先使用 tf.GradientTape 進行求導操作,然后再使用優化器的 apply_gradients 方法應用已求得的導數,進行變量值的更新。也就是說,和 TensorFlow 1.X 中優化器的 compute_gradients + apply_gradients 十分類似。同時,在 TensorFlow 2 中,無論是求導還是使用導數更新變量值,都需要顯式地指定變量。計算圖的構建代碼結構如下:

optimizer = tf.keras.optimizer.SGD(learning_rate=...)

@tf.function
def train_one_step(data):
with tf.GradientTape() as tape:
y_pred = model(data) # 模型構建
loss = ... # 計算模型的損失函數 loss
grad = tape.gradient(loss, model.variables)
optimizer.apply_gradients(grads_and_vars=zip(grads, model.variables))
在計算圖構建完成后,我們直接調用 train_one_step函數并送入訓練數據即可:
for data in dataset:
train_one_step(data)

小結
在 TensorFlow 1.X 中,我們多使用優化器的 minimize 方法,將求導和變量值更新合二為一。而在 TensorFlow 2 中,我們需要先使用 tf.GradientTape 進行求導操作,然后再使用優化器的 apply_gradients 方法應用已求得的導數,進行變量值的更新。而且在這兩步中,都需要顯式指定待求導和待更新的變量。

自動求導機制的計算圖對比 *

在本節,為了幫助讀者更深刻地理解 TensorFlow 的自動求導機制,我們以前節的 “計算?e23e8c8b55289a0c1d3b40eb1005da08.png?在?1655f326c8e18aee5a5d04b875361f3a.png時的導數” 為例,展示 TensorFlow 1.X 和 TensorFlow 2 在圖執行模式下,為這一求導過程所建立的計算圖,并進行詳細講解。

在 TensorFlow 1.X 的圖執行模式 API 中,將生成的計算圖使用 TensorBoard 進行展示:

560bd77c6f01160369200b3eba7115b5.png在計算圖中,灰色的塊為節點的命名空間(Namespace,后文簡稱 “塊”),橢圓形代表操作節點(OpNode),圓形代表常量,灰色的箭頭代表數據流。為了弄清計算圖節點 xyy_grad 與計算圖中節點的對應關系,我們將這些變量節點輸出,可見:
  • x :?
  • y : Tensor("Square:0", shape=(), dtype=float32)
  • y_grad : []

在 TensorBoard 中,我們也可以通過點擊節點獲得節點名稱。通過比較我們可以得知,變量 x 對應計算圖最下方的 x,節點 y 對應計算圖 “Square” 塊的 “ (Square) ”,節點 y_grad 對應計算圖上方 “Square_grad” 的 Mul_1 節點。同時我們還可以通過點擊節點發現,“Square_grad” 塊里的 const 節點值為 2,“gradients” 塊里的 grad_ys_0 值為 1, Shape 值為空,以及 “x” 塊的 const 節點值為 3。

接下來,我們開始具體分析這個計算圖的結構。我們可以注意到,這個計算圖的結構是比較清晰的,“x” 塊負責變量的讀取和初始化,“Square” 塊負責求平方 y = x ^ 2 ,而 “gradients” 塊則負責對 “Square” 塊的操作求導,即計算 y_grad = 2 * x。由此我們可以看出, tf.gradients 是一個相對比較 “龐大” 的操作,并非如一般的操作一樣往計算圖中添加了一個或幾個節點,而是建立了一個龐大的子圖,以應用鏈式法則求計算圖中特定節點的導數。

在 TensorFlow 2 的圖執行模式 API 中,將生成的計算圖使用 TensorBoard 進行展示:

96f65e68d9f4fa29fd0274f17a0751f3.png我們可以注意到,除了求導過程沒有封裝在 “gradients” 塊內,以及變量的處理簡化以外,其他的區別并不大。由此,我們可以看出,在圖執行模式下, tf.GradientTape這一上下文管理器的 gradient 方法和 TensorFlow 1.X 的 tf.gradients 是基本等價的。

小結
TensorFlow 1.X 中的 tf.gradients 和 TensorFlow 2 圖執行模式下的 tf.GradientTape 上下文管理器盡管在 API 層面的調用方法略有不同,但最終生成的計算圖是基本一致的。

a1e8463b8ab04756a01c89f4209a6056.png

dbedb26e4179aac206a9de6fc0eb43fa.png

“哪吒頭”—玩轉小潮流

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/276368.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/276368.shtml
英文地址,請注明出處:http://en.pswp.cn/news/276368.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

AJAX自學筆記01

從今天開始正式系統學習asp.net ajax了。XMLHttpRequest對象屬性:Number readyState (返回值4表示完成)Function onreadystatechange (執行回調函數)string responseText (返回字符串型)XMLDocument responseXML(返回XML型&#x…

如何從 0 到 1 打造團隊 PC/H5 構建工具

關注若川視野, 回復"pdf" 領取資料,回復"加群",可加群長期交流學習一、前言 大家好,我叫鰻魚,這次分享的主題是如何從 0 到 1 打造適合自己的構建部署方案。image.png先例行的自我介紹,大概 14 年…

PHP yii 框架源碼閱讀(二) - 整體執行流程分析

轉載鏈接&#xff1a;http://tech.ddvip.com/2013-11/1384432766205970.html 一 程序入口 <?php// change the following paths if necessary $yiidirname(__FILE__)./http://www.cnblogs.com/framework/yii.php; $configdirname(__FILE__)./protected/config/main.php;/…

HTTP狀態碼大全

完整的 HTTP 1.1規范說明書來自于RFC 2616&#xff0c;你可以在http://www.talentdigger.cn/home/link.php?urld3d3LnJmYy1lZGl0b3Iub3JnLw%3D%3D在線查閱。HTTP 1.1的狀態碼被標記為新特性&#xff0c;因為許多瀏覽器只支持 HTTP 1.0。你應只把狀態碼發送給支持 HTTP 1.1的客…

testng接口自動化測試_Java+Maven+TestNG接口(API)自動化測試教程(10) 使用 Jenkins 構建自動化測試持續集成...

現在代碼可以運行了&#xff0c;但是每次運行都需要我們手工去執行&#xff0c;并且測試報告也只能在執行測試的電腦上才能看到&#xff0c;我們希望能夠定時自動執行測試&#xff0c;并且能夠做到自動發送測試報告到相關人員的電子郵箱中。Jenkins 正好可以很好的完成以上訴求…

sql數據類型詳解

BCD碼1字符1/2字節 ASC碼1字符1字節 GB2312碼1字符2字節 BIG5碼1字符5字節 (1)二進制數據類型 二進制數據包括 Binary、Varbinary 和 Image  Binary 數據類型既可以是固定長度的(Binary),也可以是變長度的。  Binary[(n)] 是 n 位固定的二進制數據。其中&#xff0c;n 的取…

論公眾號內卷

關注若川視野, 回復"pdf" 領取資料&#xff0c;回復"加群"&#xff0c;可加群長期交流學習曾幾何時公眾號文章的標題單純且沒有套路七年前的我就是這樣僅僅把公眾號當做一個寫文章的博客平臺甚至是像有道云一樣的在線筆記平臺當時的標題是這樣子滴《hashma…

PHP 利用Mail_MimeDecode類提取郵件信息

轉載鏈接:http://blog.csdn.net/laijingyao881201/article/details/5512693 重點為one_mail函數。利用Mail_mimeDecode類從郵件中提取郵件頭和郵件正文。 <?php header("content-type:text/html; charsetUTF-8"); /** record kid words and insert into databa…

【轉】概要設計說明書

概要設計說明書 一&#xff0e; 引言 1&#xff0e; 編寫目的 從該階段開發正式進入軟件的實際開發階段&#xff0c;本階段完成系統的大致設計并明確系統的數據結構與軟件結構。在軟件設計階段主要是把一個軟件需求轉化為軟件表示的過程&#xff0c;這種表示只是描繪出軟件的…

程序異常異常代碼: 0xc0000005_Java基礎:看完這篇你還怕碰到異常嗎?

前言在日常的開發以及平時的學習練習中&#xff0c;異常相信對于大家來講并不陌生&#xff0c;但是對于異常的具體使用、底層實現以及分類等等可能并不是很了解。今天我就抽出了一點時間系統的整理了異常的各個知識點&#xff0c;希望能夠幫助到大家對于Java 異常的理解與學習。…

寫給初中級前端工程師的進階指南

學習一門新技術的時候&#xff0c;最大的苦惱之一&#xff0c;大概就是不知道從何入手。典型的情況是&#xff0c;你大概知道學會以后&#xff0c;這門技術可以幫你解決什么問題。但是&#xff0c;怎么才能學會、循序漸進的學習路線是什么、學習范圍有多大的深度和廣度、涉及到…

同一頁面中引入多個JS庫產生的沖突解決方案(轉)

發生JS庫沖突的主要原因&#xff1a;與jQuery庫一樣&#xff0c;許多JS庫都使用‘$’符號作為其代號。因此在一個頁面中引入多個JS庫&#xff0c;并且使用‘$’作為代號時&#xff0c;程序不能識別其代表哪個庫&#xff08;這個是我自己的解釋&#xff0c;但更深的原因就必須深…

不用安裝Oracle Client如何使用PLSQL Developer

1. 下載oracle的客戶端程序包&#xff08;30M&#xff09;只需要在Oracle下載一個叫Instant Client Package的軟件就可以了&#xff0c;這個軟件不需要安裝&#xff0c;只要解壓就可以用了&#xff0c;很方便&#xff0c;就算重裝了系統還是可以用的。下載地址&#xff1a;http…

input file的默認value清空與賦值方法

轉載鏈接&#xff1a;http://www.jb51.net/article/24872.htm出于安全性考慮&#xff0c;JS是不能直接設置File的value值的&#xff0c;下面是我總結出來的方法第1個方法是大多人傳統做法&#xff0c;替換HTML代碼&#xff0c;樓上的已經用到了&#xff0c;我不過是用正則優化一…

python中o_Python I/O與進程的詳細講解

I/Owith語句with context_expression [as target(s)]:with-bodycontext_expression返回值遵從上下文管理協議&#xff0c;包含__enter__()與__exit__()方法&#xff0c;as語句的target(s)得到的是__enter__()返回值&#xff0c;執行with-body后會調用上下文管理器的__exit__()方…

千層套路 - Vue 3.0 初始化源碼探秘

關注若川視野, 回復"pdf" 領取資料&#xff0c;回復"1"&#xff0c;可加群長期交流學習劉崇楨&#xff0c;微醫云服務團隊前端工程師&#xff0c;左手抱娃、右手持家的非典型碼農。9 月初 Vue.js 3.0 正式發布&#xff0c;代號 "One Piece"。大秘…

css網頁布局兼容性有哪些要點與訣竅

IE vs FFCSS 兼容要點&#xff1a;DOCTYPE 影響 CSS 處理FF: div 設置 margin-left, margin-right 為 auto 時已經居中, IE 不行FF: body 設置 text-align 時, div 需要設置 margin: auto(主要是 margin-left,margin-right) 方可居中FF: 設置 padding 后, div 會增加 height 和…

js 下拉底部加載|滑輪滾動到頁面底部ajax加載數據的實例

轉載鏈接&#xff1a;http://www.cnblogs.com/thinksley/archive/2013/05/12/3074237.html 滾動下拉到頁面底部加載數據是很多瀑布流網站的做法&#xff0c;那來看看配合jsonp是如何實現的吧&#xff0c;小菜總結記錄之用&#xff0c;高手勿噴。 當然本例子采用的是jquery庫&…

python并行for循環_Python并行執行for循環

簡介在介紹如何最簡單地利用 python 實現并行前&#xff0c;我們先來看一個簡單的代碼。words [apple, bananan, cake, dumpling]for word in words:print word上面的例子中&#xff0c;我們用一個 for 循環打印出 words 列表中的每個單詞。問題來了&#xff0c;這里我們打印完…