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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 人工智能 > pytorch >内容正文

pytorch

深度学习(11)TensorFlow基础操作七: 向前传播(张量)实战

發(fā)布時間:2023/12/15 pytorch 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 深度学习(11)TensorFlow基础操作七: 向前传播(张量)实战 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

深度學(xué)習(xí)(11)TensorFlow基礎(chǔ)操作七: 向前傳播(張量)實戰(zhàn)

  • 1. 導(dǎo)包
  • 2. 加載數(shù)據(jù)集
  • 3. 轉(zhuǎn)換數(shù)據(jù)類型
  • 4. 查看x.shape, y.shape, x.dtype, y.dtype
  • 5. 查看x和y的范圍
  • 6. 將一些無關(guān)信息屏蔽掉
  • 7. 將x中的數(shù)值設(shè)置在[0, 1]之間
  • 8. 創(chuàng)建數(shù)據(jù)集
  • 9. 創(chuàng)建迭代器
  • 10. 創(chuàng)建權(quán)值
  • 11. 前向運算
  • 12. 添加激活函數(shù)
  • 13. 計算誤差
  • 14. 設(shè)置自動求導(dǎo)功能
  • 15. 求解梯度
  • 16. 設(shè)置學(xué)習(xí)率
  • 17. 向前傳播
  • 18. 打印步數(shù)
  • 19. 每100步打印步數(shù)和loss
  • 20. 運行程序
  • 21. 再次運行
  • 附錄: 完整代碼

What we have learned

  • create tensor
  • indexing and slices
  • reshape and broadcasting
  • math operations
    Recap
  • out=relu{relu{relu[X@W1+b1]@W2+b2}@W3+b3}out=relu\{relu\{relu[X@W_1+b_1]@W_2+b_2\}@W_3+b_3\}out=relu{relu{relu[X@W1?+b1?]@W2?+b2?}@W3?+b3?}
  • pred=argmax(out)pred=argmax(out)pred=argmax(out)
  • loss=MSE(out,label)loss=MSE(out,label)loss=MSE(out,label)
  • minimizelossminimize lossminimizeloss
    • [W1′,b1′,W2′,b2′,W3′,b3′][W_1',b_1',W_2',b_2',W_3',b_3'][W1?,b1?,W2?,b2?,W3?,b3?]

1. 導(dǎo)包

import tensorflow as tf from tensorflow import keras from tensorflow.keras import datasets

2. 加載數(shù)據(jù)集

其中x.shape=[60k, 28, 28]; y.shap=[60k];

# x: [60k, 28, 28], # y: [60k] (x, y), _ = datasets.mnist.load_data()

3. 轉(zhuǎn)換數(shù)據(jù)類型

將x的數(shù)據(jù)類型轉(zhuǎn)換為Tensor,一般常用tf.float32;
將y的數(shù)據(jù)類型轉(zhuǎn)換為Tensor,y中數(shù)據(jù)為整型,所以使用tf.int32;

# 轉(zhuǎn)換數(shù)據(jù)類型 x = tf.convert_to_tensor(x, dtype=tf.float32) y = tf.convert_to_tensor(y, dtype=tf.int32)

4. 查看x.shape, y.shape, x.dtype, y.dtype

# 查看x.shape, y.shape, x.dtype, y.dtype print(x.shape, y.shape, x.dtype, y.dtype)

結(jié)果如下:

5. 查看x和y的范圍

# 查看x和y的范圍,即x和y的最大值和最小值 print(tf.reduce_min(x), tf.reduce_max(x)) print(tf.reduce_min(y), tf.reduce_max(y))

6. 將一些無關(guān)信息屏蔽掉

例如:

import osos.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'

[‘TF_CPP_MIN_LOG_LEVEL’] = ‘0’就是打印全部信息,如果[‘TF_CPP_MIN_LOG_LEVEL’] = ‘2’就是屏蔽這些信息;

7. 將x中的數(shù)值設(shè)置在[0, 1]之間

將x除以255.即可,這樣x的范圍就被設(shè)置在[0, 1]之間;

# x: [0~255] => [0~1.] x = tf.convert_to_tensor(x, dtype=tf.float32) / 255. y = tf.convert_to_tensor(y, dtype=tf.int32)

y在后面的代碼中會做one-hot處理;

8. 創(chuàng)建數(shù)據(jù)集

創(chuàng)建數(shù)據(jù)集的好處在于可以每次取一個batch,而原數(shù)據(jù)集每次只能取一個數(shù)據(jù);

# 創(chuàng)建數(shù)據(jù)集 train_db = tf.data.Dataset.from_tensor_slices((x, y)).batch(128)

9. 創(chuàng)建迭代器

# 創(chuàng)建迭代器 train_iter = iter(train_db) sample = next(train_iter)

一個sample就代表了迭代一次,也就是一個batch的數(shù)據(jù);
查看batch及sample[n]

# 查看sample[n].shape print('batch:', sample[0].shape, sample[1].shape)

結(jié)果如下:

sample[0]代表x的數(shù)據(jù),一個batch里有128張28×28的照片,所以sample[0].shape=[128, 28, 28];
sample[1]代表y的數(shù)據(jù),一個batch里有128個整型數(shù)據(jù),這些數(shù)據(jù)代表了每張圖片的標(biāo)簽,也就是[0~9],所以sample[1].shape=[128,]

10. 創(chuàng)建權(quán)值

創(chuàng)建w1和b1并初始化
w1一般按照裁剪過的正態(tài)分布來初始化; b1一般初始化為0;
初始化的過程要注意維度設(shè)置,w: [dim_in, dim_out], b: [dim_out];

# 創(chuàng)建權(quán)值 # [b, 784] => [b, 256] => [b, 128] => [b, 10] # w: [dim_in, dim_out], b: [dim_out] w1 = tf.random.truncated_normal([784, 256]) b1 = tf.zeros([256])

w2, b2, w3, b3同理;

w2 = tf.random.truncated_normal([256, 128]) b2 = tf.zeros([128]) w3 = tf.random.truncated_normal([128, 10]) b3 = tf.zeros([10])

11. 前向運算

for(x, y) in train_db:# x: [128, 28, 28]# y: [128]# 我們需要一個維度變換的操作才能將x.shape由[b, 28, 28]轉(zhuǎn)換為[b, 28*28]x = tf.reshape(x, [-1, 28*28])# x: [b, 28*28]# h1 = x@w1 + b1# [b, 784]@[784, 256] + [256] => [b, 256] + [256] => [b, 256] + [b, 256]# b會自動做broadcasting操作,當(dāng)然如過想要手動也可以按照如下操作:# h1 = x@w1 + tf.broadcast_to(b1, [x.shape[0], 256])h1 = x@w1 + b1# [b, 256] => [b, 128]h2 = h1@w2 + b2# [b, 128] => [b, 10]out = h2@w3 + b3

注: 這里的x就是剛才設(shè)置的一個batch的數(shù)據(jù);

12. 添加激活函數(shù)

使其非線性化;

h1 = x@w1 + b1 h1 = tf.nn.relu(h1) # [b, 256] => [b, 128] h2 = h1@w2 + b2 h2 = tf.nn.relu(h2) # [b, 128] => [b, 10] out = h2@w3 + b3

13. 計算誤差

(1) 將y進(jìn)行one-hot編碼

# 將y進(jìn)行one-hot編碼 y_onehot = tf.one_hot(y, depth=10)

depth=10代表一共有10類,即[0~9];
注: 將y進(jìn)行one-hot編碼這一步在數(shù)據(jù)創(chuàng)建時或者在這里都行,只要在計算誤差之前操作就行;
(2) 計算均方差

# mse = mean(sum(y-out)^2) # [b, 10] loss = tf.square(y_onehot - out)

(3) 計算誤差均值
得到一個Scalar(標(biāo)量)

# mean: scalar loss = tf.reduce_mean(loss)

14. 設(shè)置自動求導(dǎo)功能

將所有誤差計算的部分全部放入自動求導(dǎo)的功能內(nèi):

with tf.GradientTape() as tape:# x: [b, 28*28]# h1 = x@w1 + b1# [b, 784]@[784, 256] + [256] => [b, 256] + [256] => [b, 256] + [b, 256]# b會自動做broadcasting操作,當(dāng)然如過想要手動也可以按照如下操作:# h1 = x@w1 + tf.broadcast_to(b1, [x.shape[0], 256])h1 = x@w1 + b1h1 = tf.nn.relu(h1)# [b, 256] => [b, 128]h2 = h1@w2 + b2h2 = tf.nn.relu(h2)# [b, 128] => [b, 10]out = h2@w3 + b3# compute loss# out: [b, 10]# y: [b]# 將y進(jìn)行one-hot編碼y_onehot = tf.one_hot(y, depth=10)# mse = mean(sum(y-out)^2)# [b, 10]loss = tf.square(y_onehot - out)# mean: scalarloss = tf.reduce_mean(loss)

15. 求解梯度

# compute gradients grads = tape.gradient(loss, [w1, b1, w2, b2, w3, b3])

16. 設(shè)置學(xué)習(xí)率

即leaning rate,lr

lr = 1e-3

1e-3表示10^(-3),即0.001;

17. 向前傳播

w′=w?lr?gradw'=w-lr*gradw=w?lr?grad

# w1 = w1 - lr * w1_grads w1 = w1 - lr * grads[0] b1 = b1 - lr * grads[1] w2 = w2 - lr * grads[2] b2 = b2 - lr * grads[3] w3 = w3 - lr * grads[4] b3 = b3 - lr * grads[5]

這里grads是一個列表,所以grads[0]=w1, grads[1]=b1, …;

18. 打印步數(shù)

由:

for(x, y) in train_db:

變?yōu)?

for step, (x, y) in enumerate(train_db):

這樣每一步都會打印當(dāng)前步數(shù);

19. 每100步打印步數(shù)和loss

if step % 100 == 0:print(step, 'loss:', float(loss))

20. 運行程序

發(fā)現(xiàn)如下報錯:

打印grads:

print(grads)

發(fā)現(xiàn)全部為None類型:

原因: tf.GradientTape()默認(rèn)只會跟蹤類型為tf.Variable的數(shù)據(jù),但是我們在創(chuàng)建權(quán)重的時候,w1, b1, w2, b2, w3, b3為Tensor類型的數(shù)據(jù),所以我們需要使用tf.Variable()函數(shù)將這些權(quán)重進(jìn)行封裝:

# 創(chuàng)建權(quán)值 # [b, 784] => [b, 256] => [b, 128] => [b, 10] # w: [dim_in, dim_out], b: [dim_out] w1 = tf.Variable(tf.random.truncated_normal([784, 256])) b1 = tf.Variable(tf.zeros([256])) w2 = tf.Variable(tf.random.truncated_normal([256, 128])) b2 = tf.Variable(tf.zeros([128])) w3 = tf.Variable(tf.random.truncated_normal([128, 10])) b3 = tf.Variable(tf.zeros([10]))

這樣,tf.Variable()會自動跟蹤梯度信息;
再次運行,還是出現(xiàn)同樣的錯誤。
原因: w1 = w1 - lr * grads[0]
中后面的w1是剛才已經(jīng)改好的Variable類型的數(shù)據(jù),而前邊的w1卻還是Tensor類型的數(shù)據(jù),前后兩個w1是兩個不同的對象,這樣在下一次計算的時候就會出錯。
解決辦法: 使用原地更新的函數(shù)assign_sub():

w1.assign_sub(lr * grads[0]) b1.assign_sub(lr * grads[1]) w2.assign_sub(lr * grads[2]) b2.assign_sub(lr * grads[3]) w3.assign_sub(lr * grads[4]) b3.assign_sub(lr * grads[5])

其中assign_sub就是w - lrgrads[0]; assign_add就是w + lrgrads[0];
這樣就會使得數(shù)據(jù)類型保持不變;
驗證: 打印b3的數(shù)據(jù)類型

print(isinstance(b3, tf.Variable)) print(isinstance(b3, tf.Tensor))

運行結(jié)果如下:

這說明原地更新的方法成功了,b3以及其它權(quán)重已經(jīng)是Variable類型了。

21. 再次運行

運行結(jié)果如下:

可以看到,100輪迭代過后loss值為nan,這是梯度爆炸現(xiàn)象。
解決: 在初始化權(quán)重的時候,需要初始化在一個較好的范圍內(nèi)。原來的truncated_normal()滿足均值為0,方差為1的正態(tài)分布,我們需要將其方差變小,在truncated_normal()里設(shè)置參數(shù)stddev=0.1:

# 創(chuàng)建權(quán)值 # [b, 784] => [b, 256] => [b, 128] => [b, 10] # w: [dim_in, dim_out], b: [dim_out] w1 = tf.Variable(tf.random.truncated_normal([784, 256], stddev=0.1)) b1 = tf.Variable(tf.zeros([256])) w2 = tf.Variable(tf.random.truncated_normal([256, 128], stddev=0.1)) b2 = tf.Variable(tf.zeros([128])) w3 = tf.Variable(tf.random.truncated_normal([128, 10], stddev=0.1)) b3 = tf.Variable(tf.zeros([10]))

運行程序,結(jié)果如下:

可以看到,梯度爆炸問題得到了非常明顯的改善。所以說,在深度學(xué)習(xí)中,每一個參數(shù)對于整個結(jié)果影響是非常大的。
從運行結(jié)果可以看出,loss在不斷下降,完成了對60k張圖片的一次完整的迭代,如果想要多迭代幾次,可以再添加一個epoch循環(huán):

for epoch in range(10): # iterate db for 10for step, (x, y) in enumerate(train_db): … if step % 100 == 0:print(epoch, step, 'loss:', float(loss))

運行結(jié)果如下:

從這兩次運行結(jié)果可以看出,多輪epoch迭代要比單次迭代的效果好很多。

參考文獻(xiàn):
[1] 龍良曲:《深度學(xué)習(xí)與TensorFlow2入門實戰(zhàn)》

附錄: 完整代碼

import tensorflow as tf from tensorflow import keras from tensorflow.keras import datasets import osos.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'# x: [60k, 28, 28], # y: [60k] (x, y), _ = datasets.mnist.load_data() # 轉(zhuǎn)換數(shù)據(jù)類型 # x: [0~255] => [0~1.] x = tf.convert_to_tensor(x, dtype=tf.float32) / 255. y = tf.convert_to_tensor(y, dtype=tf.int32) # 查看x.shape, y.shape, x.dtype, y.dtype print(x.shape, y.shape, x.dtype, y.dtype) # 查看x和y的范圍,即x和y的最大值和最小值 print(tf.reduce_min(x), tf.reduce_max(x)) print(tf.reduce_min(y), tf.reduce_max(y)) # 創(chuàng)建數(shù)據(jù)集 train_db = tf.data.Dataset.from_tensor_slices((x, y)).batch(128) # 創(chuàng)建迭代器 train_iter = iter(train_db) sample = next(train_iter) # 查看sample[n].shape print('batch:', sample[0].shape, sample[1].shape)# 創(chuàng)建權(quán)值 # [b, 784] => [b, 256] => [b, 128] => [b, 10] # w: [dim_in, dim_out], b: [dim_out] w1 = tf.Variable(tf.random.truncated_normal([784, 256], stddev=0.1)) b1 = tf.Variable(tf.zeros([256])) w2 = tf.Variable(tf.random.truncated_normal([256, 128], stddev=0.1)) b2 = tf.Variable(tf.zeros([128])) w3 = tf.Variable(tf.random.truncated_normal([128, 10], stddev=0.1)) b3 = tf.Variable(tf.zeros([10]))lr = 1e-3for epoch in range(10): # iterate db for 10for step, (x, y) in enumerate(train_db): # for every batch# x: [128, 28, 28]# y: [128]# 我們需要一個維度變換的操作才能將x.shape由[b, 28, 28]轉(zhuǎn)換為[b, 28*28]x = tf.reshape(x, [-1, 28*28])with tf.GradientTape() as tape: # tf.Variable# x: [b, 28*28]# h1 = x@w1 + b1# [b, 784]@[784, 256] + [256] => [b, 256] + [256] => [b, 256] + [b, 256]# b會自動做broadcasting操作,當(dāng)然如過想要手動也可以按照如下操作:# h1 = x@w1 + tf.broadcast_to(b1, [x.shape[0], 256])h1 = x@w1 + b1h1 = tf.nn.relu(h1)# [b, 256] => [b, 128]h2 = h1@w2 + b2h2 = tf.nn.relu(h2)# [b, 128] => [b, 10]out = h2@w3 + b3# compute loss# out: [b, 10]# y: [b]# 將y進(jìn)行one-hot編碼y_onehot = tf.one_hot(y, depth=10)# mse = mean(sum(y-out)^2)# [b, 10]loss = tf.square(y_onehot - out)# mean: scalarloss = tf.reduce_mean(loss)# compute gradientsgrads = tape.gradient(loss, [w1, b1, w2, b2, w3, b3])# print(grads)# w1 = w1 - lr * w1_gradsw1.assign_sub(lr * grads[0])# w1 = w1 - lr * grads[0]b1.assign_sub(lr * grads[1])# b1 = b1 - lr * grads[1]w2.assign_sub(lr * grads[2])# w2 = w2 - lr * grads[2]b2.assign_sub(lr * grads[3])# b2 = b2 - lr * grads[3]w3.assign_sub(lr * grads[4])# w3 = w3 - lr * grads[4]b3.assign_sub(lr * grads[5])# b3 = b3 - lr * grads[5]# print(isinstance(b3, tf.Variable))# print(isinstance(b3, tf.Tensor))if step % 100 == 0:print(epoch, step, 'loss:', float(loss))

總結(jié)

以上是生活随笔為你收集整理的深度学习(11)TensorFlow基础操作七: 向前传播(张量)实战的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。