Python從零開始(庫的安裝與初步使用3+習題1.6)
前言:
這個MarkDown編輯器真糾結,我以為上面的儲存到線上草稿箱就是儲存到我的草稿箱,結果MarkDown的草稿箱就只有一個,相當於快取,會自動覆蓋上一個,也就是說不能同時進行兩個筆記。之前寫了好多都沒了,又得從新寫。
正文:
上次的問題解決了,它說wheel pyyaml出了錯,我自己去http://www.lfd.uci.edu/~gohlke/pythonlibs/下一個pyyaml裝上就好了(這個連線要複製貼上到地址框,不能從csdn轉過去,{額外問題1}):
我查了一下,pyyaml是用於Python的Yaml(一種語言)解析器和發射器(emitter 是什麼意思?{問題1})。wheel是用來代替egg的壓縮包。不過為什麼它需要執行這一部而不是直接安裝呢{問題2}?
之後做《神經。。。》那本書上的1.5實驗,具體細節我在閱讀筆記上說明。
首先是樣本資料生成,我計劃訓練樣本和測試樣本各生成2個檔案,一個數據一個標籤:
import random
import math
#開啟檔案
training_sample=open("training_sample.txt",'w')
training_label=open("training_label.txt",'w')
test_sample=open("test_sample.txt",'w')
test_label=open("test_label.txt",'w')
#下面是樣本資料生成演算法
#三個引數
r=10
w=6
d=0
#進入迴圈
i=1
while i<3000+1:
#在方形空間中隨機生成一點
x=random.uniform(-(w/2)-r,2*r+(w/2))
y=random.uniform(-(w/2)-r-d,r+(w/2))
#如果此點在任一半月形區域內,則寫入相應檔案,i加1,否則拋棄並從新生成
if (r-(w/2))**2<=x**2+y**2<=(r+(w/2))**2 and y>0:
if i>1000:
test_sample.write(str(x)+' '+str(y)+'\n' )
test_label.write('1\n')
else:
training_sample.write(str(x)+' '+str(y)+'\n')
training_label.write('1\n')
i=i+1
else:
if (r-(w/2))**2<=(x-r)**2+(y+d)**2<=(r+(w/2))**2 and y<-d:
if i>1000:
test_sample.write(str(x)+' '+str(y)+'\n')
test_label.write('-1\n')
else:
training_sample.write(str(x)+' '+str(y)+'\n')
training_label.write('-1\n')
i=i+1
#儲存並關閉檔案
training_sample.close()
training_label.close()
test_sample.close()
test_label.close()
另外,我試著用了C++裡的檔案操作,竟然成功了,看來Python的檔案操作幾乎和C++一樣,這裡的檔案開啟模式為寫“w”。寫入字串時先用str()把數值轉換成字串,官網又上不去了,所以我就參考了http://www.cnblogs.com/Joseph-AMI/p/4713003.html
字串中空格代表向量的下一維,換行代表下一向量。
Python的運算子優先順序:
運算子 描述
lambda Lambda表示式
or 布林“或”
and 布林“與”
not x 布林“非”
in,not in 成員測試
is,is not 同一性測試
<,<=,>,>=,!=,== 比較
| 按位或
^ 按位異或
& 按位與
<<,>> 移位
+,- 加法與減法
*,/,% 乘法、除法與取餘
+x,-x 正負號
~x 按位翻轉
** 指數
x.attribute 屬性參考
x[index] 下標
x[index:index] 定址段
f(arguments…) 函式呼叫
(experession,…) 繫結或元組顯示
[expression,…] 列表顯示
{key:datum,…} 字典顯示
‘expression,…’ 字串轉換
之後檢測一下資料:
import matplotlib.pyplot as plt
import numpy as np
training_sample=np.loadtxt("training_sample.txt")
plt.scatter(training_sample[:,0],training_sample[:,1])
plt.show()
結果顯示資料正常:
接下來是建模訓練:
import numpy as np
from keras.models import Sequential
from keras.layers import Dense
from keras.optimizers import SGD
from keras import backend, metrics
#建立了新類,繼承SGD
class SGD_c(SGD):
#添加了一個引數linear_decay
def __init__(self, lr=0.01, momentum=0., decay=0.,linear_decay=0.,
nesterov=False, **kwargs):
self.linear_decay = linear_decay
super(SGD_c, self).__init__(lr, momentum, decay,
nesterov, **kwargs)
#先處理線性衰減,之後進入父類函式
def get_updates(self, loss, params):
lr_t = self.lr
if self.linear_decay > 0:
self.lr -= self.linear_decay * backend.get_value(self.iterations)
self.updates = super(SGD_c, self).get_updates(loss, params)
self.lr = lr_t
return self.updates
#讀入資料
training_sample=np.loadtxt("training_sample.txt")
training_label=np.loadtxt("training_label.txt",'int')
test_sample=np.loadtxt("test_sample.txt")
test_label=np.loadtxt("test_label.txt",'int')
#建立模型
model=Sequential()
#新增一層全連線層,一個節點,輸入向量的維度為2,啟用函式為tanh
model.add(Dense(1, input_dim=2, activation='tanh'))
#損失就是書中的MSE,優化器為自己改的SGD,其引數為初始學習率和和線性衰減
model.compile(loss='mean_squared_error', optimizer=SGD_c(lr=0.1, linear_decay=(0.1-0.00001)/50), metrics=[metrics.binary_accuracy])
#model.get_layer(index=1).set_weights([np.array([[0],[1]]), np.array([0])])
#訓練模型,反覆50次
model.fit(training_sample, training_label, epochs=50, batch_size=1000)
#評估模型,列印評估結果
print(model.evaluate(test_sample, test_label, batch_size=2000))
#列印決策邊界
print(model.get_layer(index=1).get_weights())
結果如下:
前幾次迭代:
最後幾次迭代,加上評估結果與決策邊界:
(最後的決策邊界為:-0.01782304x+1.84150457y+0.00046315=0,接近x軸)
我注意到個小細節,loadtxt會把[[a],[b],[c]….]1*n這種資料讀成一維的資料串。我在官方文件看到了其dtype 引數的介紹:
dtype : data-type, optional
Data-type of the resulting array; default: float. If this is a structured data-type, the resulting array will be 1-dimensional, and each row will be interpreted as an element of the array. In this case, the number of columns used must match the number of fields in the data-type.
上面說當讀入的是結構化資料時,結果會轉換成一維資料,各行會變為一維陣列的各元素。
我在Keras官網文件看了一圈,沒找到閾值啟用函式,我就先用tanh代替了,之前的題目也證明了其效果。
並且也沒有書中的損失函式:
Keras裡所有可用loss的引數都是真實分類結果與預測分類結果。沒辦法,就用均方差代替吧。
優化器中也沒有書中所說的批梯度下降,但是有一個隨機梯度下降(SGD),我在https://www.cnblogs.com/eniac1946/p/7423865.html中大概瞭解了一下,發現也可以用來代替,但是要把batch_size設定成總樣本數。
def get_updates(self, loss, params):
grads = self.get_gradients(loss, params)
self.updates = [K.update_add(self.iterations, 1)]
lr = self.lr
if self.initial_decay > 0:
lr *= (1. / (1. + self.decay * K.cast(self.iterations, K.dtype(self.decay))))
cast的作用是把iterations轉換成decay的格式。可以看到在第一次計算學習率時衰減已經計算在內了。以每次學習的學習率為中介,線性衰減值的計算如下:
其中,i為當前學習的次數(即當前是第i次迭代),ηi為第i次學習的學習率,m為最大學習次數(50),d為衰減值。轉換後得:
但是如果要修改程式碼的話就不需要這樣再轉換一下,就像程式裡的一樣。
我看了原始碼,用於計算和返回的是函式裡的區域性lr,所以我就乾脆先把self.lr改了,等它計算完再改回來。
結語:
有幾點還是沒明白:
1,官方文件說evaluate()的batch_size預設是32,可是評估要這個是做什麼用的?{問題3}
2,用vs除錯Python程式碼時,除錯到斷點後各種變數的值我看不懂,因為本次已經耽誤了很久了,所以我也沒有搞的很明白,變數都是用print等函式打印出來看的。Python變數的儲存方法還是要研究研究。{問題4}
3,可以看到我在程式碼中一段註釋掉的程式碼:
model.get_layer(index=1).set_weights([np.array([[0],[1]]), np.array([0])])
這行程式碼是用來設定初始權值的,可以把初始的決策邊界設定成y=0(即x軸)。因為我之前生成資料時沒有生成邊界資料,所以如果這樣設定了,理論上應該是分類正確率應該是1,但為什麼總差一點呢?{問題5}而且一共有2000個測試樣本,理論上正確率應該是0.0005的整數倍,而不是像上面那樣這麼多小數位。
4,如上,我把初始的決策邊界設定成y=0,把標籤改成1和0,並且啟用函式改用sigmoid,之後正確率就正常地為1了。改了標籤之後,sigmoid和tanh不應該是一樣的嗎,為什麼有區別?{問題6}
終於告一段落了,接下來就要好好琢磨《神經網路。。。》的第二章了。
歡迎回答我留下的問題。不過如果有問題也歡迎來向我提問。