0.摘要
對輸入值x,標籤y,模型參數c,我們希望習得一個最優的Model-c滿足y=Model(x,c)
。機器學習的任務就是要確定這個Model中的參數。但是因爲Model的形狀(如層數,節點個數等)是離散的,處理起來相對麻煩,所以我們在這裏只討論可導的參數c(tensorflow的一個優勢就在於可以自動求導)。我們希望對於一個確定確定的模型Model,我們要找到這樣的c滿足c=argmin(loss)
,其中loss表示損失函數,如loss=sum(square(y-Model(x,c)))
。我們算到這一步之後,可以再根據loss對各參數的偏導用梯度下降法更新梯度,也就是我們的學習過程,更新所用的對象爲optimizer。
簡而言之,訓練分爲如下幾步:
1.y_pred=Model(x,c)
2.L=loss(y_pred,y)
3.g=optimizer(DL/Dc)
4.c=c-g
在下文中,Section1介紹瞭如何準備測試數據(傻瓜下載法);Section2,3介紹瞭如何構造一個訓練用的Model。這個Model,就是我們在tensorflow中直接用於訓練的對象。在深度學習中,這個Model就是神經網絡,而神經網絡又由許多層狀結構組成,這就是我們構造過程中的次級對象layer;Section4介紹瞭如何構造一個Optimizer;Section5是訓練的過程;Section6則是數據評估。
Talk is cheap,先從引入必要的庫開始。
#引入庫,開啓eager模式
import tensorflow as tf
import numpy as np
tf.enable_eager_execution()
1.數據準備
__init__ |
__call__ |
---|---|
下載名爲mnist的數據庫,並且分出4塊 | 從訓練集中隨機抽取batch_size個訓練數據 |
class DataLoader():
def __init__(self):
mnist=tf.contrib.learn.datasets.load_dataset("mnist")
self.train_data=mnist.train.images
self.train_label=np.asarray(mnist.train.labels,dtype=np.int32)
self.eval_data = mnist.test.images
self.eval_labels = np.asarray(mnist.test.labels, dtype=np.int32)
def __call__(self,batch_size):
index=np.random.randint(np.shape(self.train_data)[0],size=batch_size)
return self.train_data[index,:],self.train_label[index]
2.自定義層
__init__ |
__call__ |
---|---|
構造一個確定輸入輸入的全連接層,並生成對應初始數據 | 用該層對輸入值X進行計算並返回計算值 |
class FullConnectedLayer(tf.keras.layers.Layer):
def __init__(self,input_num,output_num):
super().__init__()
self.output_num=output_num
self.input_num=input_num
self.w=self.add_variable(name='w',shape=[self.input_num,self.output_num],initializer=tf.random_uniform_initializer(minval=0.,maxval=0.1))
self.b=self.add_variable(name='b',shape=[1,self.output_num],initializer=tf.random_uniform_initializer(minval=0.,maxval=0.1))
def __call__(self,X):
y_pred=tf.nn.sigmoid(tf.matmul(X,self.w)+self.b)
return y_pred
3.自定義模型
__init__ |
__call__ |
predict |
---|---|---|
繼承父類,構造複合層結構 | 用各層計算輸入值input,返回預測值 | 利用argmax 函數得到對應數據的標籤 |
class MLP(tf.keras.Model):
def __init__(self):
super().__init__()
self.dense1=tf.keras.layers.Dense(100,activation=tf.nn.relu)
self.dense2=tf.keras.layers.Dense(10)
def __call__(self,input):
x=self.dense1(input)
x=self.dense2(x)
return x
def predict(self,input):
logits=self(input)
return tf.argmax(logits,axis=-1)
4.自定義優化器
翻來覆去就那麼幾個,正常情況下直接用api就可以了。特殊情況?你除了用Adam和偶爾用上幾次SGD之外還用得着啥?實在不行徒手寫一個就行了。其實是懶得寫了。
5.訓練
#1 | #2 | #3 |
---|---|---|
定義超參數 | 實例化模型,數據,優化器 | 用tf.GradientTape()函數自動求導,optimizer和model訓練 |
#1
epoch=1000
batch_size=32
eta=0.003
#2
mlp=MLP()
data_loader=DataLoader()
optimizer=tf.train.AdamOptimizer(learning_rate=eta)
#3
for i in range(epoch):
X,y=data_loader(batch_size)
with tf.GradientTape() as tape:
y_pred=mlp(tf.convert_to_tensor(X))
L=tf.losses.sparse_softmax_cross_entropy(labels=y,logits=y_pred)
g=tape.gradient(L,mlp.variables)
optimizer.apply_gradients(grads_and_vars=zip(g,mlp.variables))
6.評估
y_pred=mlp.predict(data_loader.eval_data).numpy()
print("acc:%f"%(sum(y_pred==data_loader.eval_labels)/np.shape(data_loader.eval_labels)[0]))