最基础的发送邮件的代码

首先我们看最简单的用python实现发邮件功能的代码,运行以下代码可以实现向指定的接收邮箱发送一个主题为“Training finished”,正文内容为test的邮件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import smtplib
from email.mime.text import MIMEText
from email.header import Header
from email.mime.image import MIMEImage
from email.mime.multipart import MIMEMultipart

def send_email(subject="No subject", content="I am boring"):
mail_host = "smtp.163.com" # 邮箱的设置里的服务器地址
mail_user = "*****@163.com" # 发送邮件的邮箱
mail_pw = "*********" # 授权码,邮箱设置里开启POP3/SMTP服务,提供给你的密钥
sender = "******@163.com" # 发送邮件的邮箱,
receiver = "******@icloud.com" # 接收邮件的邮箱

# Create the container (outer) email message.
msg = MIMEText(content, "plain", "utf-8")
msg['Subject'] = subject
msg['From'] = sender
msg['To'] = receiver

try:
smtp = smtplib.SMTP_SSL(mail_host, 994) # 实例化smtp服务器
smtp.login(mail_user, mail_pw) # 登录
smtp.sendmail(sender, receiver, msg.as_string())
print("Email send successfully")
except smtplib.SMTPException:
print("Error: email send failed")

if __name__ == '__main__':
send_email(subject="Training finished", content="Test")

其中,mail_host为邮箱的服务器地址,我们可以在邮箱的POP3/SMTP/IMAP设置页面里找到。

mail_user为发送邮件的邮箱,负责将你的训练结果作为邮件发出去。

mail_pw为邮箱的授权码,在POP3/SMTP/IMAP设置页面可以找到。选择开启IMAP/SMTP服务,安全识别后会提供给你密钥。

sendermail_user一样,发送邮件的邮箱

receiver为接收邮件的邮箱。

运用到训练脚本

以下代码是将发送邮件的代码加入到swin transformer的运行脚本中。

代码的第13-38行,111,117,123,134行是加入的自动发送邮件的脚本。

实现的是全部的epoch训练结束后,将每个epoch的损失和准确率发送到指定的邮箱里。

如果需要每个epoch训练完都发送一次邮件的话,可以自己稍微改一下for循环那里。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
import os
import argparse

import torch
import torch.optim as optim
from torch.utils.tensorboard import SummaryWriter
from torchvision import transforms

from my_dataset import MyDataSet
from model import swin_base_patch4_window7_224 as create_model
from utils import read_split_data, train_one_epoch, evaluate

import smtplib
from email.mime.text import MIMEText
from email.header import Header
from email.mime.image import MIMEImage
from email.mime.multipart import MIMEMultipart

def send_email(subject="No subject", content="I am boring"):
mail_host = "smtp.163.com" # 邮箱的设置里的服务器地址
mail_user = "*****@163.com" # 发送邮件的邮箱
mail_pw = "*********" # 授权码,邮箱设置里开启POP3/SMTP服务,提供给你的密钥
sender = "******@163.com" # 发送邮件的邮箱,
receiver = "******@icloud.com" # 接收邮件的邮箱

# Create the container (outer) email message.
msg = MIMEText(content, "plain", "utf-8")
msg['Subject'] = subject
msg['From'] = sender
msg['To'] = receiver

try:
smtp = smtplib.SMTP_SSL(mail_host, 994) # 实例化smtp服务器
smtp.login(mail_user, mail_pw) # 登录
smtp.sendmail(sender, receiver, msg.as_string())
print("Email send successfully")
except smtplib.SMTPException:
print("Error: email send failed")


def main(args):
device = torch.device(args.device if torch.cuda.is_available() else "cpu")

if os.path.exists("./weights") is False:
os.makedirs("./weights")

tb_writer = SummaryWriter()

train_images_path, train_images_label, val_images_path, val_images_label = read_split_data(args.data_path)

img_size = 224
data_transform = {
"train": transforms.Compose([transforms.RandomResizedCrop(img_size),
transforms.RandomHorizontalFlip(),
transforms.ToTensor(),
transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])]),
"val": transforms.Compose([transforms.Resize(int(img_size * 1.143)),
transforms.CenterCrop(img_size),
transforms.ToTensor(),
transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])])}

# 实例化训练数据集
train_dataset = MyDataSet(images_path=train_images_path,
images_class=train_images_label,
transform=data_transform["train"])

# 实例化验证数据集
val_dataset = MyDataSet(images_path=val_images_path,
images_class=val_images_label,
transform=data_transform["val"])

batch_size = args.batch_size
nw = min([os.cpu_count(), batch_size if batch_size > 1 else 0, 8]) # number of workers
print('Using {} dataloader workers every process'.format(nw))
train_loader = torch.utils.data.DataLoader(train_dataset,
batch_size=batch_size,
shuffle=True,
pin_memory=True,
num_workers=nw,
collate_fn=train_dataset.collate_fn)

val_loader = torch.utils.data.DataLoader(val_dataset,
batch_size=batch_size,
shuffle=False,
pin_memory=True,
num_workers=nw,
collate_fn=val_dataset.collate_fn)

model = create_model(num_classes=args.num_classes).to(device)

if args.weights != "":
assert os.path.exists(args.weights), "weights file: '{}' not exist.".format(args.weights)
weights_dict = torch.load(args.weights, map_location=device)["model"]
# 删除有关分类类别的权重
for k in list(weights_dict.keys()):
if "head" in k:
del weights_dict[k]
print(model.load_state_dict(weights_dict, strict=False))

if args.freeze_layers:
for name, para in model.named_parameters():
# 除head外,其他权重全部冻结
if "head" not in name:
para.requires_grad_(False)
else:
print("training {}".format(name))

pg = [p for p in model.parameters() if p.requires_grad]
optimizer = optim.AdamW(pg, lr=args.lr, weight_decay=5E-2)

content=''
for epoch in range(args.epochs):
# train
train_loss, train_acc = train_one_epoch(model=model,optimizer=optimizer,data_loader=train_loader,device=device,epoch=epoch)

# 将训练损失和准确率保存为字符串
content+='[train epoch:{}]loss:{:.3f},acc:{:.3f}'.format(epoch,train_loss,train_acc) + '\n'

# validate
val_loss, val_acc = evaluate(model=model,data_loader=val_loader,device=device, epoch=epoch)

# 将验证的损失和准确率保存为字符串
content+='[val epoch:{}]loss:{:.3f},acc:{:.3f}'.format(epoch,val_loss,val_acc) + '\n'

tags = ["train_loss", "train_acc", "val_loss", "val_acc", "learning_rate"]
tb_writer.add_scalar(tags[0], train_loss, epoch)
tb_writer.add_scalar(tags[1], train_acc, epoch)
tb_writer.add_scalar(tags[2], val_loss, epoch)
tb_writer.add_scalar(tags[3], val_acc, epoch)
tb_writer.add_scalar(tags[4], optimizer.param_groups[0]["lr"], epoch)

torch.save(model.state_dict(), "./weights/model-{}.pth".format(epoch))
# email,调用函数,发送邮件
send_email(subject='Training finished',content=content)


if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('--num_classes', type=int, default=2)
parser.add_argument('--epochs', type=int, default=10)
parser.add_argument('--batch-size', type=int, default=32)
parser.add_argument('--lr', type=float, default=0.0001)

# 数据集所在根目录
# https://storage.googleapis.com/download.tensorflow.org/example_images/flower_photos.tgz
parser.add_argument('--data-path', type=str,default="/content/drive/MyDrive/transformer/double/skin_photos")

# 预训练权重路径,如果不想载入就设置为空字符
parser.add_argument('--weights', type=str, default='/content/drive/MyDrive/transformer/swin_transformer/swin_base_patch4_window7_224.pth',
help='initial weights path')
# 是否冻结权重
parser.add_argument('--freeze-layers', type=bool, default=False)
parser.add_argument('--device', default='cuda:0', help='device id (i.e. 0 or 0,1 or cpu)')

opt = parser.parse_args()

main(opt)

测试结果

训练完成后,邮箱可以收到如下邮件: