前言
前几天看完了pytorch入门教程,想着要做一个小玩意巩固一下知识点,然后又想着大半年没整活了,于是就想着和虚拟主播缝合起来,还能给自己增添一点动力

本人只是本科大一非计科专业,只是在课余时间了解了一点机器学习和计算机视觉的知识,所以学的比较慢,而且可能会有比较多的错误和理解不充分

在开始做时把这个小尝试大致分为:图像预处理,制作数据集,训练模型,测试模型的识别能力和可视化

由于并没有花大量时间制作数据集(于是就只做了24个数据,一共3类,每类8张图片),再加上模型是用的最最简单的全连接神经网络,再再加上数据太少,epoch设置的又比较大,理所应当地过拟合了,所以为了整活整的有效果,就把训练集拿过来测试了…初学者水平有限捏

这篇只是记录自己第一次动手做机器学习的小玩意,偏向记录自己在动手过程中的问题和收获
代码能跑是能跑,就是比较烂,本文讲的也不会太过详细和深刻

部分代码参考:https://discuss.pytorch.org/#main-container
https://pytorch.org/tutorials/
https://www.jianshu.com/p/2d9927a70594

图像预处理

我选取了正方形的图像,然后为了之后能够进行机器学习,用python里的OpenCV对图像进行压缩处理
然后设置好图像名字然后输出到对应的文件夹
在这里用到了python的字符串格式化的知识,这一点我并不常用,很陌生…
当时参考了这个网站:https://www.jb51.net/article/232118.htm
用到的格式化输出在这篇链接网页的末尾

import cv2 as cv
from matplotlib import image
from numpy import number
for i in range (1,9):number = f"{i}"print(number)image = cv.imread("D:\\Py workprojects\\the new funny file\\photo\\one\\%s.png"%number)new_image = cv.resize(image,(100,100))number = f"{i-1}"cv.imwrite("D:\\Py workprojects\\the new funny file\\data\\train\\Diana\\%s.png"%number,new_image)cv.imwrite("D:\\Py workprojects\\the new funny file\\last_data\\test\\Diana\\%s.png"%number,new_image)for i in range (1,9):number = f"{i}"print(number)image = cv.imread("D:\\Py workprojects\\the new funny file\\photo\\two\\%s.png"%number)# image = cv.imread("D:\\Py workprojects\\the new funny file\\photo\\two\\%s.png"%number,0)new_image = cv.resize(image,(100,100))number = f"{i-1}"cv.imwrite("D:\\Py workprojects\\the new funny file\\data\\train\\Taffy\\%s.png"%number,new_image)cv.imwrite("D:\\Py workprojects\\the new funny file\\last_data\\test\\Taffy\\%s.png"%number,new_image)for i in range (1,9):number = f"{i}"print(number)image = cv.imread("D:\\Py workprojects\\the new funny file\\photo\\three\\%s.png"%number)new_image = cv.resize(image,(100,100))number = f"{i-1}"cv.imwrite("D:\\Py workprojects\\the new funny file\\data\\train\\Wenjing\\%s.png"%number,new_image)cv.imwrite("D:\\Py workprojects\\the new funny file\\last_data\\test\\Wenjing\\%s.png"%number,new_image)

到此第一个.py文件结束

制作数据集

在网上乱查时发现了一个制作数据集的小网站,看起来有实用价值,不过我最后没用的上
还是放出来:https://www.makesense.ai/
使用方法比较简单,这其实就是你手动分类后生成一个csv文件,记录着文件名和label,不用再自己写文件输出了,也就方便了这一点,不过他输出的label是带“[]”的

后来的参考是:https://www.jianshu.com/p/2d9927a70594
放代码:

from random import sample
import numpy as np
from torch import nn, relu
from skimage import io
from skimage import transform
import matplotlib.pyplot as plt
import os
import torch
import torchvision
from torch.utils.data import Dataset, DataLoader
from torchvision.transforms import transforms
from torchvision.utils import make_gridclass MyDataset(Dataset):def __init__(self, root_dir, names_file, transform=None):self.root_dir = root_dirself.names_file = names_fileself.transform = transformself.size = 0self.names_list = []if not os.path.isfile(self.names_file):print(self.names_file + "does not exist!")file = open(self.names_file)for f in file:self.names_list.append(f)self.size += 1def __len__(self):return self.sizedef __getitem__(self, idx):image_path = self.root_dir + self.names_list[idx].split(" ")[0]if not os.path.isfile(image_path):print(image_path + "does not exist!")return Noneimage = io.imread(image_path) # use skitimagelabel = int(self.names_list[idx].split(" ")[1])sample = {"image": image, "label": label}if self.transform:sample = self.transform(sample)return image,label,sampleclass Resize(object):def __init__(self, output_size: tuple):self.output_size = output_sizedef __call__(self, sample):# 图像image = sample['image']# 使用skitimage.transform对图像进行缩放image_new = transform.resize(image, self.output_size)return {'image': image_new, 'label': sample['label']}
# # 变换ToTensor
class ToTensor(object):def __call__(self, sample):image = sample['image']image_new = np.transpose(image, (2, 0, 1))return {'image': torch.from_numpy(image_new),'label': sample['label']}
# 使用DataLoader可以利用多线程,batch,shuffle等
# 对原始的训练数据集进行变换
train_dataset = MyDataset(root_dir='./data/train',names_file='./data/train/labels_train.txt',# names_file='./data/train/train.txt',transform=None)transformed_trainset = MyDataset(root_dir='./data/train',names_file='./data/train/labels_train.txt',transform=transforms.Compose([Resize((100,100)),ToTensor()]))
trainset_dataloader = DataLoader(dataset=transformed_trainset,batch_size=4,shuffle=True,num_workers=0)
# Windows实现不了多线程,所以num_workers设置为0
testset_dataloader = DataLoader(dataset=transformed_trainset,batch_size=4,shuffle=True,num_workers=0)

在这一部分遇见的问题还是比较多的
下面一一记录:

自定义数据集的返回值

由于在之后可视化的需求(我对可视化了解很少,于是是照搬的前面链接文章的可视化方法),将上文文章中自定义数据集的返回值进行了更改

更改了这部分代码:

   def __getitem__(self, idx):image_path = self.root_dir + self.names_list[idx].split(" ")[0]if not os.path.isfile(image_path):print(image_path + "does not exist!")return Noneimage = io.imread(image_path) # use skitimagelabel = int(self.names_list[idx].split(" ")[1])sample = {"image": image, "label": label}if self.transform:sample = self.transform(sample)return image,label,sample

原文的return是只有sample,其实只有这个也可以用,不过在写分类器的时候用的是返回image和label

问题一:我对于后面加载数据时的train_dataset和trainset_dataloader之间的关系和使用不是太理解

也是因为这些在后面可视化过程中频繁出现报错,于是就通过加一个返回值笨拙地解决了这个问题

然后就是后面的实例化:

class Resize(object):def __init__(self, output_size: tuple):self.output_size = output_sizedef __call__(self, sample):# 图像image = sample['image']# 使用skitimage.transform对图像进行缩放image_new = transform.resize(image, self.output_size)return {'image': image_new, 'label': sample['label']}
# # 变换ToTensor
class ToTensor(object):def __call__(self, sample):image = sample['image']image_new = np.transpose(image, (2, 0, 1))return {'image': torch.from_numpy(image_new),'label': sample['label']}
# 使用DataLoader可以利用多线程,batch,shuffle等
# 对原始的训练数据集进行变换
train_dataset = MyDataset(root_dir='./data/train',names_file='./data/train/labels_train.txt',# names_file='./data/train/train.txt',transform=None)transformed_trainset = MyDataset(root_dir='./data/train',names_file='./data/train/labels_train.txt',transform=transforms.Compose([Resize((28,28)),ToTensor()]))
trainset_dataloader = DataLoader(dataset=transformed_trainset,batch_size=4,shuffle=True,num_workers=0)
# Windows实现不了多线程,所以num_workers设置为0
testset_dataloader = DataLoader(dataset=transformed_trainset,batch_size=4,shuffle=True,num_workers=0)
问题二:在这里留下的疑问点是transform和target_transform发挥的作用

在这里解决了之前的问题,batch_size是在数据集实例化时设置的
除此之外,对于Windows系统无法进行多进程num_workers=0即设置为0

训练模型

承接着上面的代码,下部分为

if torch.cuda.is_available:device = "cuda"print("cuda加速已开启")
else:device = "cpu"class NeuralNetwork(nn.Module):def __init__(self):super(NeuralNetwork, self).__init__()self.flatten = nn.Flatten()self.linear_relu_stack = nn.Sequential(nn.Linear(100*100*3, 512),nn.ReLU(),nn.Linear(512, 16),nn.ReLU(),nn.Linear(16,3))def forward(self, x):x = self.flatten(x).to(device)logits = self.linear_relu_stack(x.float())return logitsmodel = NeuralNetwork().to(device)
# model.load_state_dict(torch.load('data_Vtuber'))
# model.eval()
#
learning_rate = 1e-6
#
def train_loop(trainset_dataloader, model, loss_fn, optimizer):size = len(trainset_dataloader)for batch, (X,y,i) in enumerate(trainset_dataloader):# Compute prediction and losspred = model(X)loss = loss_fn(pred, y.to(device))# Backpropagationoptimizer.zero_grad()loss.backward()optimizer.step()if batch % 1 == 0:loss, current = loss.item(), (batch+1) * len(X)print(f"loss: {loss:>7f}  [{current:>5d}/{size*trainset_dataloader.batch_size:>5d}]")def test_loop(testset_dataloader, model, loss_fn):size = len(testset_dataloader)num_batches = len(testset_dataloader)test_loss, correct = 0, 0with torch.no_grad():for X, y, i in trainset_dataloader:pred = model(X)test_loss += loss_fn(pred, y.to(device)).item()correct += (pred.argmax(1) == y.to(device)).type(torch.float).sum().item()# softmax_0=nn.Softmax(dim = 1)# print(f"机器对每组判断的准确率的判定:\n{softmax_0(pred)}")# print(softmax_0(pred)[1][1])print(f"实际上是:\n{y}\n 机器预测的是:\n{pred.argmax(1)}")test_loss /= num_batches*testset_dataloader.batch_sizecorrect /= size*testset_dataloader.batch_sizeprint(f"Test Error: \n Accuracy: {(100*correct):>0.1f}%, Avg loss: {test_loss:>8f} \n")loss_fn = nn.CrossEntropyLoss()
optimizer = torch.optim.SGD(model.parameters(), lr=learning_rate)epochs = 10
for t in range(epochs):print(f"Epoch {t+1}\n-------------------------------")train_loop(trainset_dataloader, model, loss_fn, optimizer)test_loop(testset_dataloader, model, loss_fn)
torch.save(model.state_dict(),'data_Vtuber_complete')
print("结束咧!")

这部分之前了解的比较多,从官网基础教程中复制后也只需要改改接口和很少的代码就能使用,需要注意的就是几部分:

cuda

if torch.cuda.is_available:device = "cuda"print("cuda加速已开启")
else:device = "cpu"

我用的是30系N卡,所以可以设置cuda加速

神经网络

        self.linear_relu_stack = nn.Sequential(nn.Linear(100*100*3, 512),nn.ReLU(),nn.Linear(512, 16),nn.ReLU(),nn.Linear(16,3))

这就是用线性分类器和非线性激活函数连接的一个全连接神经网络
要注意的是,比如说我一共有N个类别,而且在这个网络之后不再有分类器来对特征值进行运算,那最后就应该用这个网络把图像(输入tensor)映射在N个值上面,由此能够预测出之后的图像属于哪一类

学习率

前面用的是梯度下降算法来进行参数的优化,在这里需要设置重要参数学习率的值

optimizer = torch.optim.SGD(model.parameters(), lr=learning_rate)

epochs

就是数据集学习几遍,过高会使模型过拟合

epochs = 10

测试模型的识别能力和可视化

前面模型构建完后,经过不停地调参,优化出一个还算满意的模型然后保存,用于下一个识别图像时进行读取
(其实这个调参使loss收敛是最最最重要的过程,这能让模型真正的有实用价值,我之后还需要学习这方面)
这部分代码和前面的差不多,只是把train的部分去掉了,增加了可视化的部分

import numpy as np
from torch import Tensor, nn, relu
from skimage import io
from skimage import transform
import matplotlib.pyplot as plt
import os
import torch
import torchvision
from torch.utils.data import Dataset, DataLoader
from torchvision.transforms import transforms
from torchvision.utils import make_grid
from zmq import deviceclass MyDataset(Dataset):def __init__(self, root_dir, names_file, transform=None):self.root_dir = root_dirself.names_file = names_fileself.transform = transformself.size = 0self.names_list = []if not os.path.isfile(self.names_file):print(self.names_file + "does not exist!")file = open(self.names_file)for f in file:self.names_list.append(f)self.size += 1def __len__(self):return self.sizedef __getitem__(self, idx):image_path = self.root_dir + self.names_list[idx].split(" ")[0]if not os.path.isfile(image_path):print(image_path + "does not exist!")return Noneimage = io.imread(image_path) # use skitimagelabel = int(self.names_list[idx].split(" ")[1])sample = {"image": image, "label": label}if self.transform:sample = self.transform(sample)return image,label,sampleclass Resize(object):def __init__(self, output_size: tuple):self.output_size = output_sizedef __call__(self, sample):# 图像image = sample['image']# 使用skitimage.transform对图像进行缩放image_new = transform.resize(image, self.output_size)return {'image': image_new, 'label': sample['label']}
# # 变换ToTensor
class ToTensor(object):def __call__(self, sample):image = sample['image']image_new = np.transpose(image, (2, 0, 1))return {'image': torch.from_numpy(image_new),'label': sample['label']}class NeuralNetwork(nn.Module):def __init__(self):super(NeuralNetwork, self).__init__()self.flatten = nn.Flatten()self.linear_relu_stack = nn.Sequential(nn.Linear(100*100*3, 512),nn.ReLU(),nn.Linear(512, 16),nn.ReLU(),nn.Linear(16,3))def forward(self, x):x = self.flatten(x).to(device)logits = self.linear_relu_stack(x.float())return logitsdevice = "cpu"
# if torch.cuda.is_available:
#     device = "cuda"
# else:
#     device = "cpu"test_dataset = MyDataset(root_dir='./last_data/test',names_file = './last_data/test/test.txt',transform=None)transformed_trainset = MyDataset(root_dir='./last_data/test',names_file='./last_data/test/test.txt',transform=transforms.Compose([Resize((100,100)),ToTensor()]))
testset_dataloader = DataLoader(dataset=transformed_trainset,batch_size=1,shuffle=True,num_workers=0)model = NeuralNetwork().to(device)
model.load_state_dict(torch.load('data_Vtuber_complete'))
model.eval()def test_loop(testset_dataloader, model, loss_fn):size = len(testset_dataloader)num_batches = len(testset_dataloader)test_loss, correct = 0, 0with torch.no_grad():plt.figure()num = 0for X, y ,i in testset_dataloader:pred = model(X)test_loss += loss_fn(pred, y.to(device)).item()correct += (pred.argmax(1) == y.to(device)).type(torch.float).sum().item()softmax_0=nn.Softmax(dim = 1)result_tenor = softmax_0(pred)result_np = np.array(result_tenor)y_np = np.array(y)pred_np = np.array(pred.argmax(1))# print(result_np)if y_np[0] == 0:name_Vtuber = "Diana"elif y_np[0] == 1:name_Vtuber = "Wenjing"elif y_np[0] == 2:name_Vtuber == "Taffy"if pred_np[0] ==0:name_Vtuber_pre = "Diana"elif pred_np[0] == 1:name_Vtuber_pre = "Wenjing"elif pred_np[0] == 2:name_Vtuber_pre = "Taffy"def show_images_batch(sample_batched):images_batch, labels_batch =\sample_batched['image'], sample_batched['label']grid = make_grid(images_batch)plt.title('The prediction result of AI is:  {}'.format(name_Vtuber_pre))plt.imshow(grid.numpy().transpose(1, 2, 0))# 这一行代码不懂捏show_images_batch(i)plt.axis('off')plt.ioff()plt.show()test_loss /= num_batches*testset_dataloader.batch_sizecorrect /= size*testset_dataloader.batch_sizeprint(f"Test Error: \n Accuracy: {(100*correct):>0.1f}%, Avg loss: {test_loss:>8f} \n")loss_fn = nn.CrossEntropyLoss()epochs = 1
for t in range(epochs):print(f"\n-------------------------------")test_loop(testset_dataloader, model, loss_fn)
plt.pause(10)
print("结束咧!")
tips:我这里用回CPU是因为之后把tensor转化为np.array时提示要先塞进CPU里,试了一次不行后我懒得再查,所以索性用CPU了(这也是一个未来需要再查的小问题)

可视化

这段可视化基本上借鉴于前面制作数据集时的文章,还需要之后再学相关的知识
这段可视化是放在了test循环里面

  softmax_0=nn.Softmax(dim = 1)result_tenor = softmax_0(pred)result_np = np.array(result_tenor)y_np = np.array(y)pred_np = np.array(pred.argmax(1))# print(result_np)if y_np[0] == 0:name_Vtuber = "Diana"elif y_np[0] == 1:name_Vtuber = "Wenjing"elif y_np[0] == 2:name_Vtuber == "Taffy"if pred_np[0] ==0:name_Vtuber_pre = "Diana"elif pred_np[0] == 1:name_Vtuber_pre = "Wenjing"elif pred_np[0] == 2:name_Vtuber_pre = "Taffy"def show_images_batch(sample_batched):images_batch, labels_batch =\sample_batched['image'], sample_batched['label']grid = make_grid(images_batch)plt.title('The prediction result of AI is:  {}'.format(name_Vtuber_pre))plt.imshow(grid.numpy().transpose(1, 2, 0))# 这一行代码不懂捏show_images_batch(i)plt.axis('off')plt.ioff()plt.show()
问题三:==之前自己可视化时出现的问题时维度问题,这个问题应该是在那个“def show_images_batch(sample_batched)”函数里解决了,没太看懂这部分,应该是用最后一行的transpose解决的,详细的留在之后再看 ==

可视化效果

最后大致的实现效果如图:
每张图片会依次出现,点击X实现交互后会出现下一张图片


【图像识别】训练一个最最简单的AI使其识别Vtuber相关推荐

  1. TensorFlow笔记(3)——利用TensorFlow和MNIST数据集训练一个最简单的手写数字识别模型...

    前言 当我们开始学习编程的时候,第一件事往往是学习打印"Hello World".就好比编程入门有Hello World,机器学习入门有MNIST. MNIST是一个入门级的计算机 ...

  2. 如何训练一个简单的语音识别网络模型---基于TensorFlow

    这篇文章是翻译自Google的教程:还有一部分没完成,但今天上去发现登录不了,只好先发这部分上来. 欢迎有兴趣学习的朋友,与我交流.微信:18221205301 如何训练一个简单的语音识别网络模型 准 ...

  3. 手把手教你用MindSpore训练一个AI模型!

    首先我们要先了解深度学习的概念和AI计算框架的角色(https://zhuanlan.zhihu.com/p/463019160),本篇文章将演示怎么利用MindSpore来训练一个AI模型.和上一章 ...

  4. ML-Agents与训练达不到目的AI的斗争史-如何用unity训练一个类吸血鬼幸存者自动躲避AI(探讨,暂时非成功经验)1.0

    问题:如何用unity训练一个类吸血鬼幸存者自动躲避AI. 我的想法: 应该抓住问题的根源解决:类吸血鬼幸存者游戏的躲避的目的是使血量维持一个健康值,所以我的逻辑是对训练的AI所有奖励(AddRewa ...

  5. 用飞桨框架2.0造一个会下五子棋的AI模型——从小白到高手的训练之旅

    点击左上方蓝字关注我们 [飞桨开发者说]洪伟,建筑行业BIM工程师.一级注册建造师,飞桨开发者,人工智能技术爱好者,相信"AI,正在让世界变得更美好",感兴趣的方向有:强化学习(R ...

  6. 使用 PyTorch 数据读取,JAX 框架来训练一个简单的神经网络

    使用 PyTorch 数据读取,JAX 框架来训练一个简单的神经网络 本文例程部分主要参考官方文档. JAX简介 JAX 的前身是 Autograd ,也就是说 JAX 是 Autograd 升级版本 ...

  7. 如何写一个游戏AI(四)如何使用卷积神经网络训练一个斗地主AI

    经过3个星期得努力,终于初步达成效果,由于训练数据少(因为我在公司使用的电脑只能使用CPU训练,所以数据不能太多,否则就要很长时间)训练出了个傻子.之后我便没有在继续这个工作了.原因有二:1.我身后的 ...

  8. 【Pytorch分布式训练】在MNIST数据集上训练一个简单CNN网络,将其改成分布式训练

    文章目录 普通单卡训练-GPU 普通单卡训练-CPU 分布式训练-GPU 分布式训练-CPU 租GPU服务器相关 以下代码示例基于:在MNIST数据集上训练一个简单CNN网络,将其改成分布式训练. 普 ...

  9. 练习推导一个最简单的BP神经网络训练过程【个人作业/数学推导】

    写在前面: 各式资料中关于BP神经网络的讲解已经足够全面详尽,故不在此过多赘述.本文重点在于由一个"最简单"的神经网络练习推导其训练过程,和大家一起在练习中一起更好理解神经网络训练 ...

最新文章

  1. Framework 动态库加载 xib
  2. 区域经济、地理信息、互联网三者交叉之行业背景分析
  3. 全城瘫痪!因韩国电信公司大火 首尔陷断网危机
  4. 互联网IP路由的逐跳全局最优化原则-Dijkstra算法证明
  5. Android—设计模式原则及常见的设计模式
  6. 侵犯软件著作权罪量刑标准
  7. PyTorch学习记录-1PyTorch安装
  8. 2015蓝桥杯C++A:饮料换购
  9. Windows10临时关闭数字签名认证
  10. 从零开始搭二维激光SLAM --- 基于ceres的后端优化的代码实现
  11. 【性能测试】:操作NMON的shell脚本
  12. http抓包实践--(七)-fiddler弱网环境
  13. java下标和相等的矩阵_39.数组中数值和下标相等的元素
  14. 数据库__配置ODBC及附加数据库的方法
  15. Centos8[Linux]下载安装qq音乐,亲测可行
  16. AutoCAD二次开发基础(二):曲线操作
  17. 虚拟化: 物理CPU与VCPU的关系 || 内存上限说起 VMware内存分配初探
  18. Java提升反射效率
  19. 1005打印任务取消不了 hp_HP打印机打印时任务打印不了时无法取消
  20. Android基于百度OCR识别图片中的文字

热门文章

  1. 访问量大为什么服务会崩溃,崩溃的本质是什么?
  2. 虚拟服务器透传步骤,esp8266透传模式设置操作步骤
  3. 2018OKR年中回顾
  4. 《房产测量规范》面积测算解释
  5. Unity实现多屏分屏效果(新手向)
  6. SAP Hybris 123 官方网站视频讲解
  7. 2023最新SSM计算机毕业设计选题大全(附源码+LW)之java医院住院管理系统7lio5
  8. 2022安全员-C证操作证考试题及模拟考试
  9. MDK 5设置黑色背景教程
  10. 鄱.阳.湖.近期SAR和光学卫星遥感数据汇总及共享