新聞中心
使用Pytorch 1.x和Tensorflow 2.x比較自動(dòng)差異和動(dòng)態(tài)模型子類方法

公司主營(yíng)業(yè)務(wù):成都網(wǎng)站設(shè)計(jì)、成都網(wǎng)站制作、外貿(mào)網(wǎng)站建設(shè)、移動(dòng)網(wǎng)站開(kāi)發(fā)等業(yè)務(wù)。幫助企業(yè)客戶真正實(shí)現(xiàn)互聯(lián)網(wǎng)宣傳,提高企業(yè)的競(jìng)爭(zhēng)能力。創(chuàng)新互聯(lián)是一支青春激揚(yáng)、勤奮敬業(yè)、活力青春激揚(yáng)、勤奮敬業(yè)、活力澎湃、和諧高效的團(tuán)隊(duì)。公司秉承以“開(kāi)放、自由、嚴(yán)謹(jǐn)、自律”為核心的企業(yè)文化,感謝他們對(duì)我們的高要求,感謝他們從不同領(lǐng)域給我們帶來(lái)的挑戰(zhàn),讓我們激情的團(tuán)隊(duì)有機(jī)會(huì)用頭腦與智慧不斷的給客戶帶來(lái)驚喜。創(chuàng)新互聯(lián)推出曲沃免費(fèi)做網(wǎng)站回饋大家。
> Source: Author
數(shù)據(jù)科學(xué)界是一種充滿活力和合作的空間。我們從彼此的出版物中學(xué)到,辯論關(guān)于論壇和在線網(wǎng)點(diǎn)的想法,并分享許多代碼(和許多)代碼。這種合作精神的自然副作用是遇到同事使用的不熟悉工具的高可能性。因?yàn)槲覀儾辉谡婵罩泄ぷ?,所以在給定的主題領(lǐng)域中獲得熟悉多種語(yǔ)言和圖書(shū)館的熟悉程度往往是有意義的,以便合作和學(xué)習(xí)最有效。
這并不奇怪,那么,許多數(shù)據(jù)科學(xué)家和機(jī)器學(xué)習(xí)工程師在其工具箱中有兩個(gè)流行的機(jī)器學(xué)習(xí)框架:Tensorflow和Pytorch。這些框架 - 在Python中 - 分享許多相似之處,也以有意義的方式分歧。這些差異,例如它們?nèi)绾翁幚鞟PI,加載數(shù)據(jù)和支持專業(yè)域,可以在兩個(gè)框架繁瑣且效率低下之間交替。這是一個(gè)問(wèn)題,給出了這兩個(gè)工具的常見(jiàn)。
因此,本文旨在通過(guò)專注于創(chuàng)建和訓(xùn)練兩個(gè)簡(jiǎn)單模型的基礎(chǔ)知識(shí)來(lái)說(shuō)明Pytorch和Tensorflow之間的差異。特別是,我們將介紹如何使用來(lái)自Pytorch 1.x的模塊API和來(lái)自Tensorflow 2.x的模塊API使用動(dòng)態(tài)子類模型。我們將查看這些框架的自動(dòng)差異如何,以提供非常樸素的梯度下降的實(shí)現(xiàn)。
但首先,數(shù)據(jù)
因?yàn)槲覀儗W⒂谧詣?dòng)差分/自動(dòng)求導(dǎo)功能的核心(作為一種進(jìn)修,是可以自動(dòng)提取函數(shù)的導(dǎo)數(shù)的容量并在一些參數(shù)上應(yīng)用梯度,以便使用這些參數(shù)梯度下降)我們可以從最簡(jiǎn)單的模型開(kāi)始,是線性回歸。我們可以使用Numpy庫(kù)使用一點(diǎn)隨機(jī)噪聲生成一些線性數(shù)據(jù),然后在該虛擬數(shù)據(jù)集上運(yùn)行我們的模型。
- def generate_data(m=0.1, b=0.3, n=200):
- x = np.random.uniform(-10, 10, n)
- noise = np.random.normal(0, 0.15, n)
- y = (m * x + b ) + noise
- return x.astype(np.float32), y.astype(np.float32)
- x, y = generate_data()
- plt.figure(figsize = (12,5))
- ax = plt.subplot(111)
- ax.scatter(x,y, c = "b", label="samples")
模型
一旦我們擁有數(shù)據(jù),我們就可以從Tensorflow和Pytorch中的原始代碼實(shí)現(xiàn)回歸模型。為簡(jiǎn)單起見(jiàn),我們不會(huì)最初使用任何層或激活器,僅定義兩個(gè)張量,W和B,表示線性模型Y = Wx + B的權(quán)重和偏置。
正如您所看到的,除了API名稱的幾個(gè)差異之外,兩個(gè)模型的類定義幾乎相同。最重要的區(qū)別在于,Pytorch需要一個(gè)明確的參數(shù)對(duì)象來(lái)定義由圖捕獲的權(quán)重和偏置張量,而TensoRFlow能夠自動(dòng)捕獲相同的參數(shù)。實(shí)際上,Pytorch參數(shù)是與模塊API一起使用時(shí)具有特殊屬性的Tensor子類:它們會(huì)自動(dòng)向模塊參數(shù)列表添加SELF,因此SECRES在參數(shù)()迭代器中出現(xiàn)。
這兩個(gè)框架都提取了從此類定義和執(zhí)行方法生成圖所需的一切(__call__或轉(zhuǎn)發(fā)),并且如下,如下所示,計(jì)算實(shí)現(xiàn)bospropagation所需的漸變。
Tensorflow動(dòng)態(tài)模型
- class LinearRegressionKeras(tf.keras.Model):
- def __init__(self):
- super().__init__()
- self.w = tf.Variable(tf.random.uniform(shape=[1], -0.1, 0.1))
- self.b = tf.Variable(tf.random.uniform(shape=[1], -0.1, 0.1))
- def __call__(self,x):
- return x * self.w + self.b
Pytorch動(dòng)態(tài)模型
- class LinearRegressionPyTorch(torch.nn.Module):
- def __init__(self):
- super().__init__()
- self.w = torch.nn.Parameter(torch.Tensor(1, 1).uniform_(-0.1, 0.1))
- self.b = torch.nn.Parameter(torch.Tensor(1).uniform_(-0.1, 0.1))
- def forward(self, x):
- return x @ self.w + self.b
構(gòu)建訓(xùn)練循環(huán),backpropagation和優(yōu)化器
使用這些簡(jiǎn)單的Tensorflow和Bytorch模型建立,下一步是實(shí)現(xiàn)損失函數(shù),在這種情況下只是意味著平方錯(cuò)誤。然后,我們可以實(shí)例化模型類并運(yùn)行訓(xùn)練循環(huán)以實(shí)現(xiàn)幾個(gè)周期。
同樣,由于我們專注于核心自動(dòng)差分/自動(dòng)求導(dǎo)功能,這里的目的是使用TensorFlow和特定于Pytorch特定的自動(dòng)Diff實(shí)現(xiàn)構(gòu)建自定義訓(xùn)練循環(huán)。這些實(shí)施方式計(jì)算簡(jiǎn)單的線性函數(shù)的梯度,并用天真梯度下降優(yōu)化器手動(dòng)優(yōu)化權(quán)重和偏置參數(shù),基本上最小化了在每個(gè)點(diǎn)處使用可微差函數(shù)之間計(jì)算的實(shí)際點(diǎn)和預(yù)測(cè)之間計(jì)算的損失。
對(duì)于TensorFlow訓(xùn)練循環(huán),我明確地使用GradientTape API來(lái)跟蹤模型的前向執(zhí)行和逐步損耗計(jì)算。我使用GradientTape的漸變來(lái)優(yōu)化權(quán)重和偏置參數(shù)。Pytorch提供了一種更“神奇的”自動(dòng)求導(dǎo)方法,隱式地捕獲參數(shù)張量的任何操作,并提供用于優(yōu)化權(quán)重和偏置參數(shù)的梯度,而無(wú)需調(diào)用另一API。一旦我具有權(quán)重和偏置梯度,在Pytorch和Tensorflow上實(shí)現(xiàn)自定義梯度下降方法就像從這些梯度中減去權(quán)重和偏置參數(shù)一樣簡(jiǎn)單,乘以恒定的學(xué)習(xí)速率。
請(qǐng)注意,由于Pytorch自動(dòng)實(shí)現(xiàn)自動(dòng)差分/自動(dòng)求導(dǎo),因此在計(jì)算后向傳播之后,有必要明確調(diào)用no_grad api。這指示Pytorch不計(jì)算權(quán)重和偏置參數(shù)的更新操作的梯度。我們還需要明確釋放在前向操作中計(jì)算的先前自動(dòng)計(jì)算的漸變,以阻止Pytorch自動(dòng)累積較批次和循環(huán)迭代中的漸變。
Tensorflow訓(xùn)練循環(huán)
- def squared_error(y_pred, y_true):
- return tf.reduce_mean(tf.square(y_pred - y_true))
- tf_model = LinearRegressionKeras()
- [w, b] = tf_model.trainable_variables
- for epoch in range(epochs):
- with tf.GradientTape() as tape:
- predictions = tf_model(x)
- loss = squared_error(predictions, y)
- w_grad, b_grad = tape.gradient(loss, tf_model.trainable_variables)
- w.assign(w - w_grad * learning_rate)
- b.assign(b - b_grad * learning_rate)
- if epoch % 20 == 0:
- print(f"Epoch {epoch} : Loss {loss.numpy()}")
Pytorch訓(xùn)練循環(huán)
- def squared_error(y_pred, y_true):
- return torch.mean(torch.square(y_pred - y_true))
- torch_model = LinearRegressionPyTorch()
- [w, b] = torch_model.parameters()
- for epoch in range(epochs):
- y_pred = torch_model(inputs)
- loss = squared_error(y_pred, labels)
- loss.backward()
- with torch.no_grad():
- w -= w.grad * learning_rate
- b -= b.grad * learning_rate
- w.grad.zero_()
- b.grad.zero_()
- if epoch % 20 == 0:
- print(f"Epoch {epoch} : Loss {loss.data}")
Pytorch和Tensorflow模型重用可用層
既然我展示了如何從Pytorch和Tensorflow中的原始代碼實(shí)現(xiàn)線性回歸模型,我們可以查看如何使用密集和線性層,從TensorFlow和Pytorch庫(kù)中重新實(shí)現(xiàn)相同的型號(hào)。
帶現(xiàn)有圖層的TensoRFlow和Pytorch動(dòng)態(tài)模型
您將在模型初始化方法中注意到,我們正在用TensorFlow中的密集層替換W和B參數(shù)的顯式聲明和Pytorch中的線性層。這兩個(gè)層都實(shí)現(xiàn)了線性回歸,并且我們將指示它們使用單個(gè)權(quán)重和偏置參數(shù)來(lái)代替以前使用的顯式W和B參數(shù)。密集和線性實(shí)現(xiàn)將在內(nèi)部使用我們之前使用的相同的張解聲明(分別為tf.variable和nn.parameter)來(lái)分配這些張量并將它們與模型參數(shù)列表相關(guān)聯(lián)。
我們還將更新這些新模型類的呼叫/前進(jìn)方法,以替換具有密度/線性層的手動(dòng)線性回歸計(jì)算。
- class LinearRegressionKeras(tf.keras.Model):
- def __init__(self):
- super().__init__()
- self.linear = tf.keras.layers.Dense(1, activation=None) # , input_shape=[1]
- def call(self, x):
- return self.linear(x)
- class LinearRegressionPyTorch(torch.nn.Module):
- def __init__(self):
- super(LinearRegressionPyTorch, self).__init__()
- self.linear = torch.nn.Linear(1, 1)
- def forward(self, x):
- return self.linear(x)
具有可用優(yōu)化器和損耗函數(shù)的訓(xùn)練
既然我們已經(jīng)使用現(xiàn)有圖層重新實(shí)現(xiàn)了我們的Tensorflow和Pytorch型號(hào),我們可以專注于如何構(gòu)建更優(yōu)化的訓(xùn)練循環(huán)。我們不是使用我們以前的Na?ve實(shí)現(xiàn),我們將使用這些庫(kù)可用的本機(jī)優(yōu)化器和損失函數(shù)。
我們將繼續(xù)使用之前觀察到的自動(dòng)差分/自動(dòng)求導(dǎo)功能,但此時(shí)具有標(biāo)準(zhǔn)漸變下降(SGD)優(yōu)化實(shí)現(xiàn)以及標(biāo)準(zhǔn)損耗功能。
Tensorflow訓(xùn)練循環(huán),易于擬合方法
在Tensorflow中,F(xiàn)IT()是一種非常強(qiáng)大,高級(jí)別的訓(xùn)練模型方法。它允許我們用單個(gè)方法替換手動(dòng)訓(xùn)練循環(huán),該方法指定超級(jí)調(diào)整參數(shù)。在調(diào)用fit()之前,我們將使用Compile()方法編譯模型類,然后通過(guò)梯度后代優(yōu)化器和用于訓(xùn)練的損失函數(shù)。
您會(huì)注意到在這種情況下,我們將盡可能多地重用來(lái)自TensorFlow庫(kù)的方法。特別是,我們將通過(guò)標(biāo)準(zhǔn)隨機(jī)梯度下降(SGD)優(yōu)化器和標(biāo)準(zhǔn)的平均絕對(duì)誤差函數(shù)實(shí)現(xiàn)(MEAL_ABSOLUTE_ERROR)到編譯方法。一旦模型進(jìn)行編譯,我們最終可以撥打擬合方法來(lái)完全訓(xùn)練我們的模型。我們將通過(guò)數(shù)據(jù)(x和y),epochs的數(shù)量以及每個(gè)時(shí)代使用的批量大小。
帶有自定義循環(huán)和SGD優(yōu)化器的TensoRFLOF訓(xùn)練循環(huán)
在以下代碼段中,我們將為我們的模型實(shí)施另一個(gè)自定義訓(xùn)練循環(huán),這次盡可能多地重用由Tensorflow庫(kù)提供的損失函數(shù)和優(yōu)化器。您會(huì)注意到我們的前自定義Python損失函數(shù)替換為tf.losses.mse()方法。我們初始化了TF.keras.optimizers.sgd()優(yōu)化程序而不是用漸變手動(dòng)更新模型參數(shù)。調(diào)用Optimizer.apply_gradient()并傳遞權(quán)重和偏置元組列表將使用漸變更新模型參數(shù)。
- tf_model_train_loop = LinearRegressionKeras()
- optimizer = tf.keras.optimizers.SGD(learning_ratelearning_rate=learning_rate)
- for epoch in range(epochs * 3):
- x_batch = tf.reshape(x, [200, 1])
- with tf.GradientTape() as tape:
- y_pred = tf_model_train_loop(x_batch)
- y_pred = tf.reshape(y_pred, [200])
- loss = tf.losses.mse(y_pred, y)
- grads = tape.gradient(loss, tf_model_train_loop.variables)
- optimizer.apply_gradients(grads_and_vars=zip(grads, tf_model_train_loop.variables))
- if epoch % 20 == 0:
- print(f"Epoch {epoch} : Loss {loss.numpy()}")
具有自定義循環(huán)和SGD優(yōu)化器的Pytorch訓(xùn)練循環(huán)
與上面的上一個(gè)Tensorflow代碼段一樣,以下代碼片段通過(guò)重用Pytorch庫(kù)提供的丟失功能和優(yōu)化器來(lái)實(shí)現(xiàn)新模型的Pytorch訓(xùn)練循環(huán)。您會(huì)注意到我們將使用NN.Mseloss()方法替換我們以前的自定義Python丟失函數(shù),并初始化標(biāo)準(zhǔn)Optim.sgd()優(yōu)化程序,其中包含模型的學(xué)習(xí)參數(shù)列表。如前所述,我們將指示Pytorch從丟失向后傳播中獲取每個(gè)參數(shù)張量的關(guān)聯(lián)梯度(load.backward()),最后,我們可以通過(guò)調(diào)用來(lái)容易地更新新標(biāo)準(zhǔn)優(yōu)化器與與梯度相關(guān)聯(lián)的所有參數(shù)更新新的標(biāo)準(zhǔn)優(yōu)化器優(yōu)化器.step()方法。Pytorch使張量和梯度之間自動(dòng)關(guān)聯(lián)的方式允許優(yōu)化器檢索張量和梯度以通過(guò)配置的學(xué)習(xí)速率更新它們。
- torch_model = LinearRegressionPyTorch()
- criterion = torch.nn.MSELoss(reduction='mean')
- optimizer = torch.optim.SGD(torch_model.parameters(), lr=learning_rate)
- for epoch in range(epochs * 3):
- y_pred = torch_model(inputs)
- loss = criterion(y_pred, labels)
- optimizer.zero_grad()
- loss.backward()
- optimizer.step()
- if epoch % 20 == 0:
- print(f"Epoch {epoch} : Loss {loss.data}")
結(jié)果
正如我們所看到的那樣,TensoRFlow和Pytorch自動(dòng)差分和動(dòng)態(tài)子類API非常相似,即使它們使用標(biāo)準(zhǔn)SGD和MSE實(shí)現(xiàn)方式也是如此。當(dāng)然,這兩個(gè)模型也給了我們非常相似的結(jié)果。
在下面的代碼片段中,我們使用Tensorflow的Training_variables和Pytorch的參數(shù)方法來(lái)獲得對(duì)模型的參數(shù)的訪問(wèn),并繪制我們學(xué)習(xí)的線性函數(shù)的圖表。
- [w_tf, b_tf] = tf_model_fit.trainable_variables
- [w2_tf, b2_tf] = tf_model_train_loop.trainable_variables
- [w_torch, b_torch] = torch_model.parameters()
- w_tf = tf.reshape(w_tf, [1])
- w2_tf = tf.reshape(w2_tf, [1])
- with torch.no_grad():
- plt.figure(figsize = (12,5))
- ax = plt.subplot(111)
- ax.scatter(x, y, c = "b", label="samples")
- ax.plot(x, w_tf * x + b_tf, "r", linewidth = 5.0, label = "tensorflow fit")
- ax.plot(x, w2_tf * x + b2_tf, "y", linewidth = 5.0, label = "tensorflow train loop")
- ax.plot(x, w_torch * inputs + b_torch, "c", linewidth = 5.0, label = "pytorch")
- ax.legend()
- plt.xlabel("x1")
- plt.ylabel("y",rotation = 0)
結(jié)論
Pytorch和新Tensorflow 2.x都支持動(dòng)態(tài)圖形和自動(dòng)差分核心功能,以提取圖表中使用的所有參數(shù)的漸變。您可以輕松地在Python中實(shí)現(xiàn)訓(xùn)練循環(huán),其中包含任何損失函數(shù)和漸變后代優(yōu)化器。為了專注于兩個(gè)框架之間的真實(shí)核心差異,我們通過(guò)實(shí)施自己的簡(jiǎn)單MSE和Na?veSGD來(lái)簡(jiǎn)化上面的示例。
但是,我強(qiáng)烈建議您在實(shí)現(xiàn)任何Na?ve代碼之前重用這些庫(kù)上可用的優(yōu)化和專用代碼。
下表總結(jié)了上面示例代碼中所注明的所有差異。我希望它可以作為在這兩個(gè)框架之間切換時(shí)的有用參考。
> Source: Author
當(dāng)前題目:兩個(gè)框架的故事:pytorch與tensorflow
路徑分享:http://www.dlmjj.cn/article/cdihdhe.html


咨詢
建站咨詢
