一、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") # 不计休眠时间