1. 程式人生 > >Python從零開始(庫的安裝與初步使用3+習題1.6)

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}

終於告一段落了,接下來就要好好琢磨《神經網路。。。》的第二章了。

歡迎回答我留下的問題。不過如果有問題也歡迎來向我提問。