一、model.train()和model.eval()用法和差別
例如:定義一個網絡:
# 線性網絡
class Net(nn.Module):
def __init__(self):
super(generator, self).__init__()
self.gen = nn.Sequential(
nn.Linear(100, 256),
nn.ReLU(True),
nn.Linear(256, 256),
nn.ReLU(True),
nn.Linear(256, 784),
nn.Tanh()) # Tanh激活函數是希望生成的假的圖檔資料分布能夠在-1~1之間。
def forward(self, x):
x = self.gen(x)
return x
# 執行個體化這個網絡
model = Net()
# 訓練模式使用.train()
model.train()
# 測試模型使用.eval()
model.eval()
(1)model.train()的作用及位置:啟用 Batch Normalization 和 Dropout。
(2)model.eval()的作用:不啟用 Batch Normalization 和 Dropout。model.eval()是保證BN層能夠用全部訓練資料的均值和方差。對于Dropout,model.eval()利用了所有的網絡連接配接,即不随機舍棄神經元。
正确的位置:
for epoch in range(10):
# train
model.train()
running_loss = 0.0
t1 = time.perf_counter()
for step, data in enumerate(train_loader, start=0):
images, labels = data
images = images.to(device)
labels = labels.to(device)
optimizer.zero_grad() # 清空之前的梯度資訊
outputs = model(images)
loss = loss_function(outputs, labels) # 計算loss
#print(loss.size())
loss.backward() # 反向傳播
optimizer.step() # 更新所有的參數
# print statistics
running_loss += loss.item()
# validate
model.eval()
acc = 0.0 # accumulate accurate number / epoch
with torch.no_grad():
# 關閉 梯度更新 進而節省了GPU算力和顯存 #
for val_data in validate_loader:
val_images, val_labels = val_data
outputs = model(val_images.to(device))
predict_y = torch.max(outputs, dim=1)[1]
acc += (predict_y == val_labels.to(device)).sum().item()
val_accurate = acc / val_num
print('[epoch %d] train_loss: %.3f test_accuracy: %.3f' %
(epoch + 1, running_loss / step, val_accurate))
二、model.test() 與torch.no_grad()的差別
- 在eval模式下,dropout層會讓所有的激活單元都通過,而BN層會停止計算和更新mean和var,直接使用在訓練階段已經學出的mean和var值。
-
with torch.no_grad()則主要是用于停止autograd子產品的工作,以起到加速和節省顯存的作用。
作用是停止梯度的更新,進而節省了GPU算力和顯存,但是并不會影響dropout和BN層的行為。
參考連結
三、Python時間測試(time幫助文檔)
1. time.time() 秒
以浮點數形式傳回自紀元以來的時間(**以秒為機關**)。
紀元的具體日期和閏秒的處理取決于平台。
在 Windows 和大多數 Unix 系統上,紀元是 1970 年 1 月 1 日的 00:00:00 (UTC),閏秒不計入紀元以來的時間(以秒為機關)。
這通常稱為 Unix 時間。要找出給定平台上的紀元,請檢視 gmtime(0)。
用法:
import time
st = time.time()
time.sleep(5)
et = time.time()
print(et-st) # 秒

2. time.perf_counter() 秒
傳回性能計數器的值(以秒為機關),即具有最高可用分辨率的時鐘以測量短持續時間。
它确實包括睡眠期間經過的時間,并且是系統範圍的。
傳回值的參考點未定義,是以隻有兩次調用結果的差異才有效。
import time
t2 = time.perf_counter()
time.sleep(5)
t2 = time.perf_counter() - t2
print(f"process_time()用時:{t2} s") # 包含休眠時間
3. time.process_time() 秒
傳回目前程序的系統和使用者 CPU 時間總和的值(以秒為機關)。
它不包括睡眠期間經過的時間。
根據定義,它是流程範圍的。
傳回值的參考點未定義,是以隻有兩次調用結果之間的差異才有效。
import time
t3 = time.process_time()
time.sleep(5)
t3 = time.process_time() - t3
print(f"process_time()用時:{t3} s") # 不計休眠時間