心情抒發
了解基礎numpy、pandas、matplotlib後我們就要進入深度學習了,我在進行深度學習的訓練的時候有時是使用linux作業系統,因為我的mac M1在下載tensorflow的時候遇到很多問題,因為mac M1和之前intel版本的mac不太一樣,之前的intel版本是x86架構的,但是mac M1是arm架構的,我花了三天還是沒辦法在我的mac上下載tensorflow,因此我在做機器學習時有兩種做法,第一種是使用google的Colaboratory,另一種是使用linux,所以我幫我的ASUS灌雙系統,為何不直接用windows10呢?因為我比較喜歡mac,所以我有時會在mac上寫程式,再透過ssh的方式在linux上進行,在這裡不得不讚嘆mac的界面設計,光看到就很舒服,而linux的界面有點太舊了,看了有點不習慣,那廢話不多說就進入我們的Machine Learning。 ## Linear Regression(線性回歸)design 所謂的線性回歸就是在觀察和歸納樣本的過程中向量和函數值呈現線性的關係,那這種關係可以用一個關係式來表達: Formula: Y = X1*W1 + X2*W2 + B 其中W和X都是矩陣,代表我們的參數可以不只一個,W代表Weights(權重),B代表Bias(偏移量)。 而運用這個公式有一個缺點,就是它的數值會介於正無限大到負無限大,所以這時候會加入活化函數,這個我稍後再提。
然而我們在進行機器學習有一個很重要的目標,就是讓Loss變小,什麼是Loss呢?我來粗略的介紹一下,在解釋前先看看這兩個關係式: 1. MSE(Mean-Square Error) 2. MAE(Mean-Absolute Error)
我們在做機器學習的時候希望計算機幫我們做預測的時候誤差值越低越好,總不能我們叫它預測一個一次函數,結果它算出來的答案是三次函數吧,所以Loss是在計算電腦在進行運算時的誤差值,我們稱之為loss function,loss function有很多種,而我目前只略懂這兩種。
首先來說MSE(Mean-Square Error),MSE顧名思義,均方誤差(MSE)計算的是預測值和實際觀測值間差的平方的均值。它只考慮誤差的平均大小,不考慮其向量,前面有提到y = f(x) = wx+b,這個y是我們預測的值,而我們要減去真實數據,即可得到差值,但為何要平方?因為我們的差值有可能是負的,怕會到時相消,所以這裡將它平方,可以保證為正值,但MSE方法仍然有個小問題,在「單位的解釋」上我們有點難以解釋數據,例如身高的平方的意義是?此時我們會使用RMSE(Root Mean Squared Error)將它開根號。
接著來說MAE(Mean-Absolute Error),其實MAE和MSE觀念很像,那觀念一樣的地方我就不多做贅述,MAE和MSE的關係上只差在一個是平方,另一個則是取絕對值,既然如此為何要分這兩種呢?老實說我也不太能理解,我在網路上看資料的時候他是這樣說的,「會有「在等於0時」不可微分的問題,不可微分會有什麼問題? 簡單來說,我們會沒辦法透過微分決定ML模型的修正方向。」對於微分我不是很理解,因為正在寫此篇的我還是小高一,但也無妨,實際上在做微分這運算的不是我,而是計算機,所以我也不用太著急,但MAE完全不能使用嗎? 倒也不完全是不能用,它也是有他的優勢的,那優勢在哪,有機會再來說吧!
處理機器學習的三大步驟
在進行ML的時候常常會因為其中的一個步驟做的不好而導致訓練失敗,所以每個環節都是非常重要的。
首先第一個步驟是設定一個未知的函式,就如同Linear
regression那邊一樣,設定一個函式,再把參數加進去,算出y。
第二步,定義loss function,就如同前面所說的,後續會深入介紹。
第三步,optimization,這個步驟是很容易被遺忘的,而這個會在後面的例子中說到。
## nonlinear regression(非線性函數)
前面有提到活化函式,這個活化函式是用在線性回歸之後,這邊我使用sigmoid()函式做介紹,故公式會變成下面那個:
Formula: Y = Sigmoid(X1*W1 + X2*W2 + B)
sigmoid()是一個非線性函數,它的作用是在於使整個輸出保持在0~1之間。 ##
函數數值訓練 ### 首先先看個code: 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30import tensorflow.compat.v1 as tf
import numpy as np
import matplotlib.pyplot as plt
tf.disable_v2_behavior()
x = np.random.rand(200).astype(np.float32)
y = x*0.5+0.8
plt.plot(x,y,color = 'red')
weights = tf.Variable(tf.random.uniform([1],-1.0,1.0))
biases = tf.Variable(tf.zeros([1]))
func = weights*x + biases
loss = tf.reduce_mean(tf.square(func - y)) # MSE
optimization = tf.train.GradientDescentOptimizer(0.5)
train = optimization.minimize(loss)
init = tf.global_variables_initializer()
sess = tf.Session()
sess.run(init)
for i in range(201):
sess.run(train)
if i % 10 == 0:
plt.scatter(x,x*sess.run(weights)+sess.run(biases))
print(i,sess.run(weights),sess.run(biases))
plt.show()
接著來看函式圖形:
其中紅色那條線是我們正確的直線。
在這個圖面中可以看出電腦一開始的誤差很大,由藍色那條線可以知道,但經過200次的學習後可以使誤差變得非常小,趨近於我們正確的直線方程式:f(x)
= y = 0.5*x + 0.8,這個現象也可以從輸出資料中看到這個現象。
接著來了解程式碼,這邊介紹程式碼不會講到各個函式的細節,若要看細節請去我另一篇筆記:tensorflow,這篇會傾向實作神經網路,所以基礎要先打好再來看這篇。
### code introduction
一開始我們先import套件,由於我是自學機器學習,而tensorflow2.x有點太新,所以網路上可以學習的資源比較少,這邊才引用tensorflow
1.x版本,接著import numpy方便生成數據,然後import
matplotlib.pyplot,此套件是方便進行數據可視化。 雖然我們已經import
tensorflow
1.x版本,但是還是有可能和tensorflow2.x版本撞到,所以加入tf.disable_v2_behavior()來避免這個問題。
引用完套件後就來生成資料,首先運用numpy的生成亂數,由於在tensorflow在運算的時候大多是利用float32,所以我們這邊設定生成的變數也要是float32,由於要生成一個直線,所以要有一個直線方程式,所以我們這邊上一個方程式叫做f(x)
= y = 0.5*x +
0.8,而當我們把大量的x帶入後畫成直線即是我們要的函式圖形,而我們這次的目標是訓練計算機能預測我們的weight和bias,以達到和我們的直線最相近的值,接著我們用Variable宣告我們的weight和bias,接著將weight和bias帶入直線方程式,func
= weights*x +
biases,在前面有說過我們希望我們訓練的值和實際的值的差距能越小越好,所以我們使用loss函式來計算訓練的值和實際的值的差距,這邊使用的方式是MSE,前面說過MSE這邊就不多贅述了。
做完loss
function後就可以進行我們的optimization,由於我不會手刻神經網路,所以這邊直接使用函式,而這邊要做的optimization是使用梯度下降(GradientDescent),那什麼是梯度下降這個議題有機會我會在後面提到,所以這邊就直接引用,而他的參數我只放一個,這個參數代表他的learning_rate,而learning_rate越高或越低會造成什麼狀況我還不太明白,所以這邊就直接選擇中間值0.5來做優化。接著為了讓我們的loss變小,所以我們要進行優化減小,這裡引用minimize()來減小。
接著為了使用Variable,我們必須初始化所有Variable,接著用Session去跑,最後讓迴圈去跑,看使用者希望執行幾次,我這邊設定200次,然後每隔十次讓他輸出資料和圖形,這邊使用plt.scatter()顯示出點,最後plt.show()讓他顯示,我們就完成我們的函數數值訓練了!
## 建造一個神經網路(create a neural network) ### 首先先看code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47import tensorflow.compat.v1 as tf
import numpy as np
import matplotlib.pyplot as plt
tf.disable_v2_behavior()
def add_layer(inputs,input_size,output_size,activation_function = None):
weight = tf.Variable(tf.random_normal([input_size,output_size]))
bias = tf.Variable(tf.zeros([1,output_size])+0.1)
y0 = tf.matmul(inputs,weight) + bias
if activation_function is None:
output = y0
else:
output = activation_function(y0)
return output
x = np.linspace(-1,1,300)[:,np.newaxis]
noise = np.random.normal(0,0.05,x.shape)
y = np.square(x) - 0.5 + noise
x_data = tf.placeholder(tf.float32,[None,1])
y_data = tf.placeholder(tf.float32,[None,1])
layer1 = add_layer(x_data,1,10,activation_function = tf.nn.relu)
predict = add_layer(layer1,10,1,activation_function = None)
loss = tf.reduce_mean(tf.reduce_sum(tf.square(y_data-predict),reduction_indices = [1]))
trainning = tf.train.GradientDescentOptimizer(0.1).minimize(loss)
sess = tf.Session()
sess.run(tf.global_variables_initializer())
fig = plt.figure()
ax = fig.add_subplot(1,1,1)
ax.scatter(x,y)
plt.ion()
plt.show()
for i in range(1000):
sess.run(trainning,feed_dict = {x_data:x,y_data:y})
if i % 50 == 0:
print(sess.run(loss,feed_dict = {x_data:x,y_data:y}))
try:
ax.lines.remove(lines[0])
except Exception:
pass
predict_val = sess.run(predict,feed_dict = {x_data:x})
lines = ax.plot(x,predict_val,'r-',lw = 5)
plt.pause(0.1)
神經網路
我們基本的神經網路構造是由三種層組合而成的,分別為input layer、hidden layer、output layer,我在這邊設定我們的hidden layer有10個。 ### code introduction 首先要定義一個神經層,名稱叫做add_layer(),要傳入的參數有4個,為了滿足函數關係,我們的函數式為:y = wx+b,第一個參數是我們的x,第二個參數是我們神經元的輸入層數量,第三個參數是我們神經元輸出層數量,第四個是我們要加入的激勵函數,常見的激勵函數有:sigmoid、tanh、ReLU,負責做非線性的調整,使我們的神經元在某個部位較為特別。 接著定義我們weight和bias,我們的weight是給予亂數,而bias是給予0.1,接著算出我們的y,所以我們的y = wx+b的所有數字都齊全了,接著將他傳入激勵函數,所以要先判斷使用者是否有給予激勵函數,如果沒有,則使用預設值None,使用原本的線性函數,而如果有給予激勵函數,則會將y傳入激勵函數,最後再將結果回傳。
由於要訓練電腦做出最佳的判斷,我們必須先有一個函數式,將x輸入可得到y,而我們y不見得是完全落在我們函式圖形上,應該會有偏差,所以我們這邊加入noise,使數據有些偏差,這樣會更像真實數據。 接著建造兩個placeholder,一個是x_data另一個是y_data,而x_data是代表我們一開始生成的x,y_data是代表我們實際數據的y,將此placeholder加入我們的add_layer(),由於我們隱藏層有10個所以輸入10,且我希望我的x_data可以運用激勵函數數值縮減到0~1之間,所以這邊使用ReLU,簡單說一下ReLU是什麼ReLU是一種激勵函數,能讓原本大於1的數變成縮到0~1之間,而小於0的數自動變成0。
接著寫出loss function,這邊使用的方法是MSE,這邊比較不一樣的是reduce_sum()裡的reduction_indices是指說我們希望對哪一個維度做加總,默認值是把所有數據做加總也就是一維,而如果給予的參數是0代表是對第0維的位置做加總,以此類推。 再來是要做optimization,這裡是用的方法是Gradient Descent(梯度下降),接著將結果的loss盡可能取較小的,所以取minimize()。
由於我們希望能有數據可視化的效果,所以這邊先利用plt.figure()建立一個新的圖形,接著使用fig.add_subplot()來建造一個子圖,接著將我們實際的點用scatter()畫出散佈圖,再來用迴圈去跑,由於我不希望將所有的線條都畫出來,所以我要將前一份刪除,但在第一份資料顯示的時候沒有前一份,此時會出現error,所以這裡使用try語句,如果出現error就pass,如果沒有就將它刪除。
最後用sess.run()來跑tranning,並分別給予x_data和y_data值,同時等候0.1秒輸出一個圖,並每隔50次輸出一次結果,而我們可以看到數值下降的趨向,以及函數圖的紅色曲線越來越接近我們的真實值,代表電腦已經經過訓練了,我們的結果也完成了。
## 存取已訓練好的資料 ### 程式碼 #### 儲存: 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15import tensorflow.compat.v1 as tf
tf.disable_v2_behavior()
w = tf.Variable([[1,2,3],[4,5,6]], dtype = tf.float32, name = 'weight')
b = tf.Variable([[1,2,3]], dtype = tf.float32, name = 'bias')
init = tf.global_variables_initializer()
saver = tf.train.Saver()
with tf.Session as sess:
sess.run(init)
save_path = saver.save(sess, 'my_net/save_net.ckpt')
print('Save path: ', save_path)1
2
3
4
5
6
7
8
9
10
11
12
13import tensorflow.compat.v1 as tf
import numpy as np
tf.disable_v2_behavior()
w = tf.Variable(np.arange(6).reshape((2, 3)),dtype = tf.float32, name = 'weight')
b = tf.Variable(np.arange(3).reshape((1,3)), dtype = tf.float32, name = 'bias')
saver = tf.train.Saver()
with tf.Session() as sess:
saver.restore(sess, 'my_net/save_net.ckpt')
print("weight: ", sess.run(w))
print('bias: ', sess.run(b))1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
from tensorflow.keras.utils import to_categorical
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Conv2D, MaxPooling2D
from tensorflow.keras.layers import Dense, Flatten
from tensorflow.keras.optimizers import SGD
from tensorflow.keras.datasets import mnist
(x_train, y_train), (x_test, y_test) = mnist.load_data()
x_train = x_train.reshape(60000, 28, 28, 1) / 255
x_test = x_test.reshape(10000, 28, 28, 1) / 255
y_train = to_categorical(y_train, 10)
y_test = to_categorical(y_test, 10)
model = Sequential()
model.add(Conv2D(16, (3,3), padding='same', input_shape=(28,28,1),activation = 'relu'))
model.add(MaxPooling2D(pool_size=(2,2)))
model.add(Conv2D(32, (3,3), padding='same', activation = 'relu'))
model.add(MaxPooling2D(pool_size=(2,2)))
model.add(Conv2D(64, (3,3), padding='same', activation = 'relu'))
model.add(MaxPooling2D(pool_size=(2,2)))
model.add(Flatten())
model.add(Dense(60, activation = 'relu'))
model.add(Dense(10, activation = 'softmax'))
model.summary()
model.compile(loss = 'mse', optimizer = SGD(lr=0.087), metrics = ['accuracy'])
model.fit(x_train, y_train, batch_size = 128, epochs = 12)
result = model.predict_classes(x_test)
# result = np.argmax(model.predict(x_test), axis = -1)
loss, acc = model.evaluate(x_test, y_test)
print(f'accuracy: {acc*100:.2f}%')
def my_predict(n):
print('CNN predict: ', result[n])
X = x_test[n].reshape(28,28)
plt.imshow(X, cmap='Greys')
n = 893
my_predict(n)
plt.show()
model.save('CNNmodel.h5')
ResNet50
程式碼
1 | import numpy as np |
影像辨識
1 | import numpy as np |
RNN(情意分析)
程式碼
1 | import numpy as np |
程式碼介紹
首先引入基本套件,再來引入sequence套件,這個套件是對我們的文字做處理的,再來是Sequential,這個就是架設神經網路的框架,然後引入Dense做全連結的神經網路,這邊比較特別的是Embedding,這個是Keras很貼心的地方,這個神經層是負責降維度,再來到了RNN的重頭戲,LSTM(Long
Short-Term
Momory)是RNN的一種,其實還有另一種叫做GRU,這邊不會解釋LSTM,因為LSTM非常複雜,反正這邊就把它當作一種RNN的神經層,然後我們引入imdb,這個是網路電影資料庫,我們要從裡面提取資料,最後是get_word_index,這個是imdb裡支援的,它可以給我們得到單字的index。
再來要取得數據,我們從imdb裡提取,我們只提取10000個數字,太多數字數據會太大,然後將此向量做分割,100個數字算一組,如果未滿100個數字就補0。
再來建造神經網路和訓練與往常一樣,這邊就不多贅述了,只是這邊要注意,用colaby做的時候要開gpu,或者盡量使用有gpu運算的電腦,不然會訓練非常久。
然後我們來看看'this'這個字的index是多少,輸出時可以知道是11,然後我們輸入一個對電影的評價,並將每個字做分割並傳入做預測,此時得到的數字越大代表電腦判斷這句話是正向的,越接近0時代表這句話是反面的,最後再做儲存就完成這次的實作了。
## Tokenizer ### 程式碼 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from tensorflow.keras.preprocessing.text import Tokenizer
from urllib.request import urlretrieve
import pickle
urlretrieve("https://github.com/yenlung/Deep-Learning-Basics/raw/master/data/dream.txt", "dream.txt")
f = open('dream.txt', 'r')
lines = f.readlines()
f.close()
text_lines = [x.lstrip('\u3000\u3000') for x in lines]
text = ''.join(text_lines)
tokenizer = Tokenizer(char_level=True)
tokenizer.fit_on_texts([text])
print(tokenizer.texts_to_sequences(["人生短暫,珍惜當下"]))
print(tokenizer.sequences_to_texts([[12, 131, 804, 792, 1, 261, 403, 203, 59]]))
f = open('MyTokenizer.pkl', 'wb')
pickle.dump(tokenizer, f)
f.close()
# 開啟檔案方式:
# f = open('tokenizer.pkl', 'rb')
# tokenizer = pickle.load(f)
# f.close()