- AlexNet的代码:pytorch实现AlexNet
- 学了一下tmux的使用tmux命令,不然连接一断就没了。
- 新建tmux会话:
tmux 没有名字,默认代号为0开始
tmux new -s 名字为<>内的内容,默认代号为0开始 - 分离会话
ctrl+b d 或输入 tmux detach - 查看所有tmux会话
tmux ls - 接入会话tmux attach -t 0(<名称>)
- 杀死会话tmux kill-session -t 0(<名称>)
- 切换会话tmux switch -t 0(<名称>)
- 窗格tmux split-window(-h)分割后是同一个tmux会话,分出了不同窗口
ctrl+b x关闭当前pane窗格
-
指定device,这里的device是张量或模型被分配的位置,cpu或cuda以及具体哪一块编号。如果0号gpu存在,就分到gpu上跑、没的话就在cpu上跑。之后会有to_device,把数据传送过去。
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") -
数据转换-有一定的数据增强作用
data_transform是一个字典,包含“train”和“val”。分别代表训练集和验证集的操作。
transforms.Compose函数就是将transforms组合在一起,每一个transforms都有自己的功能。最终使用定义好的data_transforme循序处理transforms。
train:图像按照中心随机切割到224*224;随机概率水平翻转;转为tensor类型;对像素值进行归一化
val: 照比例把图像最小的一个边长放缩到224,另一边按照相同比例放缩;转为tensor类型;对像素值进行归一化data_transform = { "train": transforms.Compose([transforms.RandomResizedCrop(224), transforms.RandomHorizontalFlip(), transforms.ToTensor(), transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))]), "val": transforms.Compose([transforms.Resize((224, 224)), # cannot 224, must (224, 224) transforms.ToTensor(), transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])} -
定义和加载好测试集和验证集路径
ImageFolder的解释
参数为:
root:数据集路径;
transform:对照片预处理变换;
target_transform:对label处理,默认为0,1,2…;
loader:加载方式,默认;
is_valid_file:图像有没有损坏
返回值为:
self.classes:用一个 list 保存类别名称;[a,b,c]
self.class_to_idx:类别对应的索引,与不做任何转换返回的 target 对应;{‘a’:0,‘b’:1,…}
self.imgs:保存(图片路径, 类别) tuple的 list[(‘D:/…’,0),(‘D:…’,1)…]image_path = "path" # flower data set path train_dataset = datasets.ImageFolder(root=image_path + "/train", transform=data_transform["train"]) train_num = len(train_dataset) validate_dataset = datasets.ImageFolder(root=image_path + "/val", transform=data_transform["val"]) val_num = len(validate_dataset) -
flower_list是上面标签和对应的索引,cla_dict是索引对应的标签,相当于f的key是c的value,f的value是c的key。
flower_list = train_dataset.class_to_idx cla_dict = dict((val, key) for key, val in flower_list.items())
-
每个批大小为32,torch.utils.data.DataLoader使用解释,将一个batch封装成一个tensor
参数:
dataset (Dataset) – 决定数据从哪读取或者从何读取;
batch_size (python:int, optional) – 批尺寸(每次训练样本个数,默认为1)
shuffle (bool, optional) –每一个 epoch是否为乱序 (default: False).
num_workers (python:int, optional) – 是否多进程读取数据(默认为0);
drop_last (bool, optional) – 当样本数不能被batchsize整除时,最后一批数据是否舍弃(default: False)
pin_memory(bool, optional) - (默认为false)锁页内存解释batch_size = 32 train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=batch_size, shuffle=True, num_workers=2) validate_loader = torch.utils.data.DataLoader(validate_dataset, batch_size=batch_size, shuffle=True, num_workers=2) -
迭代验证集的iamge和label。但是后面的代码里面也没有用到test_image和test_label,我不知道有啥用QAQ
test_data_iter = iter(validate_loader) test_image, test_label = test_data_iter.next()
-
使用AlexNet神经网络,类别有5个,初始化权重。
将数据传送到device上
定义使用的损失函数
定义优化器net = AlexNet(num_classes=5, init_weights=True) net.to(device) #损失函数:这里用交叉熵 loss_function = nn.CrossEntropyLoss() #优化器 这里用Adam optimizer = optim.Adam(net.parameters(), lr=0.0002) #定义训练参数保存路径 save_path = './AlexNet.pth' #训练过程中最高准确率 best_acc = 0.0
-
循环10个epoch,在每个epoch中:
a. net.train()是因为net.train()解释
我不理解具体实现,只知道适用于训练集和测试集不一致的情况,例如dropout、BatchNorm。这里用到了dropout。
b. for step, data in enumerate(train_loader, start=0) 这句其实我有点不理解QAQ,他的意思大概是一次一次的加载每一个batch,step就是第几次,从0开始。data是一个list,data[0]是这个batch构成的tensor,data[1]是相对应的label编号。在这个数据集上,bs=32,3306张图,遍历了103次。
c. with torch.no_grad():解释
d predict_y = torch.max(outputs, dim=1)[1]返回每一行的最大值,dim=1表示行。outputs是一个batch中每个图片对每个类别的预测概率,返回的是最大的概率值和对应的索引。后面的[1]取出了索引值。
e .item()主要是把数据从tensor取出来,变成python的数据类型。这里为float。
f torch.save(net.state_dict(), save_path),保存网络的参数for epoch in range(10): # train net.train() #训练过程中,使用之前定义网络中的dropout running_loss = 0.0#初始化loss t1 = time.perf_counter()#打开计时器,计算时间 for step, data in enumerate(train_loader, start=0): images, labels = data optimizer.zero_grad() #梯度置0 outputs = net(images.to(device)) #计算输出y_pred loss = loss_function(outputs, labels.to(device))#计算loss loss.backward() #反向传播得到梯度 optimizer.step() #更新所有参数 # print statistics running_loss += loss.item() # validate net.eval() #测试过程中不需要dropout,使用所有的神经元 acc = 0.0 # accumulate accurate number / epoch with torch.no_grad(): for val_data in validate_loader: val_images, val_labels = val_data outputs = net(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 if val_accurate > best_acc: best_acc = val_accurate torch.save(net.state_dict(), save_path) print('[epoch %d] train_loss: %.3f test_accuracy: %.3f' % (epoch + 1, running_loss / step, val_accurate)) print('Finished Training')
data_transform = transforms.Compose(
[transforms.Resize((224, 224)),
transforms.ToTensor(),
transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])
2. 加载图片
touch.unsqueeze是啥:解释对tensor插入维度。原来img为3×224×224,执行完之后为1×3×224×224。不知道是不是因为训练时是一batch为单位的,网络的输入要求是4维tensor,所以增加1的这个维度,方便使用。
img = Image.open("图片路径")
plt.imshow(img) #显示图片
img = data_transform(img) #做变换
img = torch.unsqueeze(img, dim=0)
class_indict={'0': 'daisy', '1': 'dandelion', '2': 'roses', '3': 'sunflowers', '4': 'tulips'} #定义编号对应的类别
3. 设置模型
model = AlexNet(num_classes=5) model_weight_path = "./AlexNet.pth" #训练模型时保存的参数的路径 model.load_state_dict(torch.load(model_weight_path)) #加载参数 model.eval() #设置为测试状态4. 测试
with torch.no_grad(): #不对w求导
# predict class
output = torch.squeeze(model(img)) #降维删除1的维度
predict = torch.softmax(output, dim=0) #对output的数据进行处理
predict_cla = torch.argmax(predict).numpy() #返回 input 张量中所有元素的最大值的索引,再转为numpy
print(class_indict[str(predict_cla)], predict[predict_cla].item())
plt.show()



