記一次使用Tensorflow搭建神經網路模型經歷
阿新 • • 發佈:2019-01-01
隱去背景, 作者最近第一次用Tensorflow實現訓練了幾個模型, 其中遇到了一些錯誤, 把它記錄下來
前言
以下提到的所有程式碼, 都可以在github上面找到. 倉庫地址 https://github.com/spxcds/neural_network_code/
這個倉庫裡提到的幾段程式碼, 分別實現在從最簡單的lr, 到全連線神經網路, 再到卷積神經網路. 從最簡單的自己實現交叉熵損失函式, 計算L2正則化, 到後來直接呼叫庫函式, 由簡到難, 由淺入深, 截止目前為止, 只實現了MLR, MLP, LeNet-5, AlexNet, VGG-16等幾個演算法
網路結構
LeNet-5
AlexNet
程式碼實現
幾個重要的函式
卷積操作
def conv(self, input_tensor, name, kh, kw, dh, dw, n_output, padding='SAME'): n_input = input_tensor.get_shape()[-1].value kernel = tf.get_variable( name=name + 'kernel', shape=[kh, kw, n_input, n_output], dtype=tf.float32, initializer=tf.truncated_normal_initializer(stddev=0.05)) bias = tf.get_variable( name=name + 'bias', shape=[n_output], dtype=tf.float32, initializer=tf.constant_initializer(0.0)) c = tf.nn.conv2d(input_tensor, kernel, (1, dh, dw, 1), padding=padding) # SAME, VALID return tf.nn.relu(tf.nn.bias_add(c, bias), name=name)
全連線操作
def fc(self, input_tensor, name, n_output): n_input = input_tensor.get_shape()[-1].value weights = tf.get_variable( name=name + 'weights', shape=[n_input, n_output], dtype=tf.float32, initializer=tf.truncated_normal_initializer(stddev=0.05)) tf.add_to_collection('losses', tf.nn.l2_loss(weights)) # l2_lambda * tf.add_n(tf.get_collection('losses')) bias = tf.get_variable( name=name + 'bias', shape=[n_output], dtype=tf.float32, initializer=tf.constant_initializer(0.0)) return tf.nn.bias_add(tf.matmul(input_tensor, weights), bias)
交叉熵
cost_cross_entropy = tf.reduce_mean(-tf.reduce_sum(y * tf.log(tf.clip_by_value(p, 1e-10, 1.0)), axis=1))
畫圖
def plot(self, save_path):
df = pd.DataFrame(self.train_history, columns=['iterations', 'train_acc', 'val_acc', 'train_loss', 'val_loss'])
# loss曲線
fig = plt.figure(figsize=(20, 10))
ax = fig.add_subplot(121)
ax.grid(True)
ax.plot(df.iterations, df.train_loss, 'k', label='訓練集損失', linewidth=1.2, alpha=0.4)
ax.plot(df.iterations, df.val_loss, 'k--', label='驗證集損失', linewidth=2)
ax.legend(fontsize=16)
ax.set_xlabel('Iterations', fontsize=16)
ax.set_ylabel('Loss', fontsize=16)
ax.set_xlim(np.min(df.iterations), np.max(df.iterations) + 0.1, auto=True)
ax.tick_params(axis='both', which='major')
ax.set_title('損失曲線', fontsize=22)
# 混淆矩陣
fig_matrix_confusion = plt.figure(figsize=(10, 10))
ax = fig_matrix_confusion.add_subplot(111)
confusion_matrix = self.get_confusion_matrix(mnist.test.images, mnist.test.labels)
sns.heatmap(
confusion_matrix,
fmt='',
cmap=plt.cm.Greys,
square=True,
cbar=False,
ax=ax,
annot=True,
xticklabels=np.arange(10),
yticklabels=np.arange(10),
annot_kws={'fontsize': 20})
ax.set_xlabel('Predicted', fontsize=16)
ax.set_ylabel('True', fontsize=16)
ax.tick_params(labelsize=14)
ax.set_title('混淆矩陣', fontsize=22)
plt.savefig(save_path + '_confusion_matrix')
plt.close()
碰到的問題
- 網路loss幾乎不收斂
- 學習率設定的不對, 稍微調大一點學習率就可以了
- batch_size設定的太大
- 優化演算法選一個更高階的, 原先我使用的是
tf.train.GradientDescentOptimizer
優化演算法, 跑了幾千個batch才有效果, 換成tf.train.AdamOptimizer
, 幾十個batch就開始收斂了
- 訓練一段時間後, 網路loss變為NaN
- 梯度爆炸, 使學習過程偏離了正常的學習軌跡, 這個時候調低學習率就可以了
- 計算交叉熵的時候, 出現了
log(0)*0
的;情況, 使用tf.clip_by_value(t=value,clip_value_min=1e-8,clip_value_min=1.0)
避免這種情況
- 訓練集和驗證集accuracy維持在0.1左右不變, 可能正則化引數l2_lambda設定大了, 設成1e-4左右試一下
- 全連線層的最後一層輸出層就不要加relu了, 直接加一個softmax即可