网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
秦岭神树
秦时明月
吞噬星空
从上面的样例空可以看出,不同的动漫风格差异还是很大的,下面就说说我如何实现动漫分类的。
制作数据集
=====
制作数据集,需要用到从动漫中抽取图片,抽取图片需要用到ffmpeg工具,具体的安装和使用参考:Windows安装ffmpeg,使用ffmpeg从视频中的抽取图像_AI浩-CSDN博客。
然后我们使用python,调用ffmeg实现对动漫视频的批量抽取的逻辑,在D盘中新建两个文件夹,一个文件夹命名qlss,这个文件夹存放动漫视频,一个文件夹是imags,用于存放抽取的图片。Python的代码如下:
import os
创建三个列表用来存储视频文件以及视频地址
file_list = []
file_list_path=[]
filelist = []
源文件目录
dir_path = ‘D:\qlss’
#cmd命令存入str字符串
str = 'ffmpeg ’ + ‘-i {} -ss 00:00:30 -f image2 -vf fps=1/5 -qscale:v 2 …/imags/img_{}%05d.jpg’
filenameList=os.listdir(dir_path)
print(filenameList)
for j in range(len(filenameList)):
filepath=os.path.join(dir_path,filenameList[j])
str_cmd = str.format(filepath, filenameList[j].split(‘.’)[0])
print(str_cmd)
os.popen(str_cmd)
上面代码的思路:遍历视频文件,使用Python在cmd中执行ffmpeg命令实现对图片抽取。
新建项目
新建一个图像分类的项目,data里面放数据集,dataset文件夹中自定义数据的读取方法,这次我不采用默认的读取方式,太简单没啥意思。然后再新建train.py和test.py
在项目的根目录新建train.py,然后在里面写训练代码。
导入所需要的库
=======
我这次选用的模型是inception_v3。
import torch.optim as optim
import torch
import torch.nn as nn
import torch.nn.parallel
import torch.utils.data
import torch.utils.data.distributed
import torchvision.transforms as transforms
from dataset.dataset import SeedlingData
from torch.autograd import Variable
from torchvision.models import inception_v3
设置全局参数
======
设置BatchSize、学习率和epochs,判断是否有cuda环境,如果没有设置为cpu。
设置全局参数
modellr = 1e-4
BATCH_SIZE = 32
EPOCHS = 10
DEVICE = torch.device(‘cuda’ if torch.cuda.is_available() else ‘cpu’)
图像预处理
=====
在做图像与处理时,train数据集的transform和验证集的transform分开做,train的图像处理出了resize和归一化之外,还可以设置图像的增强,比如旋转、随机擦除等一系列的操作,验证集则不需要做图像增强,另外不要盲目的做增强,不合理的增强手段很可能会带来负作用,甚至出现Loss不收敛的情况。注:inception_v3模型输入的size是3×299×299
transform = transforms.Compose([
transforms.Resize((299, 299)),
transforms.ToTensor(),
transforms.Normalize([0.5, 0.5, 0.5], [0.5, 0.5, 0.5])
])
transform_test = transforms.Compose([
transforms.Resize((299, 299)),
transforms.ToTensor(),
transforms.Normalize([0.5, 0.5, 0.5], [0.5, 0.5, 0.5])
])
读取数据
====
将数据集解压后放到data文件夹下面,如图:
然后我们在dataset文件夹下面新建 __init__.py和dataset.py,在dataset.py文件夹写入下面的代码:
说一下代码的核心逻辑。
第一步 建立字典,定义类别对应的ID,用数字代替类别。
第二步 在__init__里面编写获取图片路径的方法。测试集只有一层路径直接读取,训练集在train文件夹下面是类别文件夹,先获取到类别,再获取到具体的图片路径。然后使用sklearn中切分数据集的方法,按照7:3的比例切分训练集和验证集。
第三步 在__getitem__方法中定义读取单个图片和类别的方法,由于图像中有位深度32位的,所以我在读取图像的时候做了转换。
coding:utf8
import os
from PIL import Image
from torch.utils import data
from torchvision import transforms as T
from sklearn.model_selection import train_test_split
Labels={‘吞噬星空’: 0, ‘秦岭神树’: 1, ‘秦时明月’: 2}
class SeedlingData (data.Dataset):
def init(self, root, transforms=None, train=True, test=False):
“”"
主要目标: 获取所有图片的地址,并根据训练,验证,测试划分数据
“”"
self.test = test
self.transforms = transforms
if self.test:
imgs = [os.path.join(root, img) for img in os.listdir(root)]
self.imgs = imgs
else:
imgs_labels = [os.path.join(root, img) for img in os.listdir(root)]
imgs = []
for imglable in imgs_labels:
for imgname in os.listdir(imglable):
imgpath = os.path.join(imglable, imgname)
imgs.append(imgpath)
trainval_files, val_files = train_test_split(imgs, test_size=0.3, random_state=42)
if train:
self.imgs = trainval_files
else:
self.imgs = val_files
def getitem(self, index):
“”"
一次返回一张图片的数据
“”"
img_path = self.imgs[index]
img_path=img_path.replace(“\”,‘/’)
if self.test:
label = -1
else:
labelname = img_path.split(‘/’)[-2]
label = Labels[labelname]
data = Image.open(img_path).convert(‘RGB’)
data = self.transforms(data)
return data, label
def len(self):
return len(self.imgs)
然后我们在train.py调用SeedlingData读取数据 ,记着导入刚才写的dataset.py(from dataset.dataset import SeedlingData)
dataset_train = SeedlingData(‘data/train’, transforms=transform, train=True)
dataset_test = SeedlingData(“data/train”, transforms=transform_test, train=False)
读取数据
print(dataset_train.imgs)
导入数据
train_loader = torch.utils.data.DataLoader(dataset_train, batch_size=BATCH_SIZE, shuffle=True)
test_loader = torch.utils.data.DataLoader(dataset_test, batch_size=BATCH_SIZE, shuffle=False)
设置模型
====
使用CrossEntropyLoss作为loss,模型采用inception_v3,选用预训练模型。更改全连接层,将最后一层类别设置为3,然后将模型放到DEVICE。优化器选用Adam。
实例化模型并且移动到GPU
criterion = nn.CrossEntropyLoss()
model_ft = inception_v3(pretrained=True)
num_ftrs = model_ft.fc.in_features
model_ft.fc = nn.Linear(num_ftrs, 3)
model_ft.to(DEVICE)
选择简单暴力的Adam优化器,学习率调低
optimizer = optim.Adam(model_ft.parameters(), lr=modellr)
def adjust_learning_rate(optimizer, epoch):
“”“Sets the learning rate to the initial LR decayed by 10 every 30 epochs”“”
modellrnew = modellr * (0.1 ** (epoch // 50))
print(“lr:”, modellrnew)
for param_group in optimizer.param_groups:
param_group[‘lr’] = modellrnew
设置训练和验证
=======
inception_v3模型较早,model输出有两个参数,在这里要注意。
output,hid = model(data)
定义训练过程
def train(model, device, train_loader, optimizer, epoch):
model.train()
sum_loss = 0
total_num = len(train_loader.dataset)
print(total_num, len(train_loader))
for batch_idx, (data, target) in enumerate(train_loader):
data, target = Variable(data).to(device), Variable(target).to(device)
output,hid = model(data)
loss = criterion(output, target)
optimizer.zero_grad()
loss.backward()
optimizer.step()
print_loss = loss.data.item()
sum_loss += print_loss
if (batch_idx + 1) % 10 == 0:
print(‘Train Epoch: {} [{}/{} ({:.0f}%)]\tLoss: {:.6f}’.format(
epoch, (batch_idx + 1) * len(data), len(train_loader.dataset),
-
- (batch_idx + 1) / len(train_loader), loss.item()))
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Go语言开发知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新
{:.0f}%)]\tLoss: {:.6f}'.format(
epoch, (batch_idx + 1) * len(data), len(train_loader.dataset),
-
- (batch_idx + 1) / len(train_loader), loss.item()))
[外链图片转存中…(img-1GUKX256-1715561424253)]
[外链图片转存中…(img-U5fu60R1-1715561424253)]
[外链图片转存中…(img-7nIxvVNO-1715561424253)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Go语言开发知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新