TensorFlow+Pytorch识别阿猫阿狗(下)

简介: TensorFlow+Pytorch识别阿猫阿狗(下)

2. Pytorch版


大致思路和TensorFlow一样,只是两个框架不同api的使用上会有所区别。


import os
import torch
from torch import nn
from torch import functional as F
from torch.utils import data
from torchvision import transforms,datasets,models
import numpy as np
import time
import random
import matplotlib.pyplot as plt
from sklearn.metrics import confusion_matrix
plt.rcParams['font.sans-serif'] = ['simhei']
plt.rcParams['axes.unicode_minus'] = False
复制代码


2.1 载入数据


因为之前TensorFlow里已经下好了数据集,所以这里只用载入就好


file_path="./cats_and_dogs_filtered/"
train="train"
test="validation"
trans=transforms.Compose([
    transforms.Resize((224,224)),#随机切割将图片大小变为(224,224)
    transforms.ToTensor(), # 归一化为0-1
])
train_data=datasets.ImageFolder(os.path.join(file_path,train),trans)
test_data=datasets.ImageFolder(os.path.join(file_path,test),trans)
random_choice=random.sample([i for i in range(len(train_data))],25)
plt.figure(figsize=(10,8))
plt.suptitle("训练集可视化")
for i,j in enumerate(random_choice):
    ax = plt.subplot(5,5,i+1)
    plt.imshow(train_data[j][0].numpy().transpose((1,2,0)))
    plt.title("标签为: "+str(train_data[j][1])+" "+train_data.classes[train_data[j][1]])
    plt.axis("off")
plt.show()
batch_size=64
train_loader=data.DataLoader(train_data,batch_size=batch_size,shuffle=True)
test_loader=data.DataLoader(test_data,batch_size=batch_size,shuffle=False)
复制代码

在这里对图片处理的操作并不多,不像之前还有一系列图像增强操作。主要还是调整图片大小和归一化

image.png

2.2 模型构建与训练


有了之前的经验,我们干脆放弃花里胡哨的复杂网络,直接上基本的CNN


base_model=nn.Sequential(
    nn.Conv2d(3,48, kernel_size=7, stride=4, padding=1), nn.ReLU(),
    nn.MaxPool2d(kernel_size=3, stride=2),
    nn.Conv2d(48, 96, kernel_size=5, padding=2), nn.ReLU(),
    nn.MaxPool2d(kernel_size=3, stride=2),
    nn.Conv2d(96,128, kernel_size=3, padding=1), nn.ReLU(),
    nn.Conv2d(128,128, kernel_size=3, padding=1), nn.ReLU(),
    nn.MaxPool2d(kernel_size=3, stride=2),
    nn.Flatten(),
    nn.Linear(4608, 1024), nn.ReLU(),
    nn.Dropout(p=0.5),
    nn.Linear(1024, 512), nn.ReLU(),
    nn.Dropout(p=0.5),
    nn.Linear(512,2)
)
# 模型参数初始化
for name,param in base_model.named_parameters():
    if 'weight' in name:
        nn.init.kaiming_normal_(param)
    elif 'bias' in name:
        nn.init.constant_(param,val=0)
复制代码


各层输出如下


image.png

开始训练


epochs=40
lr=1e-4
cirterion=nn.CrossEntropyLoss()
optimizer=torch.optim.Adam(base_model.parameters(),lr=lr)
base_model=base_model.cuda()
base_model.train() 
loss_=0.
train_acc=0.
total=0.
for epoch in range(epochs):
    for i,data in enumerate(train_loader,0):
        inputs,train_labels=data
        optimizer.zero_grad()
        outputs=base_model(inputs.cuda())
        _,predicts=torch.max(outputs.data,1)
        train_acc+=(predicts.cuda()==train_labels.cuda().data).sum()
        loss=cirterion(outputs,train_labels.cuda())
        loss.backward()
        optimizer.step()
        loss_+=loss.item()
        #print(f"epoch: {epoch},loss: {loss_}")
        total+=train_labels.size(0)
    print(f"epoch: {epoch},loss={loss_/total*batch_size},acc={100*train_acc/total}%")  
复制代码


Pytorch训练起来比TensorFlow繁琐一些,需要在自己定义好损失函数以及优化器之后,进行正向传播计算损失、梯度,然后再利用优化器更新模型参数。当然,在高版本适配的Pytorch Lightning中已经实现了类似于TensorFlow.keras那样简单的compile、fit方法。不过我现在的显卡只能支持1.2,而Lightning最低要求1.3……为了使用GPU还是保持现状吧。

image.png


看看测试集上效果如何


def test(model,test_loader):
    model.eval()
    correct=0
    test_predict=[]
    with torch.no_grad():
        for idx,(t_data,t_target) in enumerate(test_loader):
            t_data,t_target=t_data.cuda(),t_target.cuda()
            pred=model(t_data)
            pred_class=pred.argmax(dim=1)
            test_predict.extend(pred_class.cpu())
            correct+=(pred_class==t_target).sum().item()
    acc=correct/len(test_data)
    print(f"测试集上准确率为: {acc*100}%")
    return test_predict
test_predict=test(base_model,test_loader)
复制代码

image.png

y_true=test_loader.dataset.targets
matrix=confusion_matrix(y_true,test_predict)
def plot_confusion_matrix(cm,classes, title='混淆矩阵'):
    plt.figure(figsize=(12, 8), dpi=100)
    np.set_printoptions(precision=2)
    # 在混淆矩阵中每格的概率值
    ind_array = np.arange(len(classes))
    x, y = np.meshgrid(ind_array, ind_array)
    for x_val, y_val in zip(x.flatten(), y.flatten()):
        c = cm[y_val][x_val]
        if c > 0.001:
            plt.text(x_val, y_val, "%0.2f" % (c,), color='red', fontsize=15, va='center', ha='center')
    plt.imshow(cm, interpolation='nearest')
    plt.title(title)
    xlocations = np.array(range(len(classes)))
    plt.xticks(xlocations, classes, rotation=90)
    plt.yticks(xlocations, classes)
    plt.ylabel('真实值')
    plt.xlabel('预测值')
    plt.show()
plot_confusion_matrix(matrix,list(test_loader.dataset.class_to_idx))
复制代码

image.png

效果和之前TensorFlow中的差不太多,那再试试迁移学习


transfer_model=models.densenet201(pretrained=True)
for param in transfer_model.parameters():
    param.requires_grad=False
transfer_model.classifier=nn.Sequential(
    nn.Linear(1920,512),
    nn.LeakyReLU(0.1),
    nn.Linear(512,128),
    nn.Dropout(0.5),
    nn.Linear(128,2)
)
transfer_model=transfer_model.cuda()
optimizer=torch.optim.Adam(transfer_model.parameters(),lr=lr)
epochs = 10
transfer_model.train()
loss_=0.
train_acc=0.
total=0.
for epoch in range(epochs):
    for i,data in enumerate(train_loader):
        inputs,train_labels=data
        optimizer.zero_grad()
        outputs=transfer_model(inputs.cuda())
        _,predicts=torch.max(outputs.data,1)
        train_acc+=torch.sum(predicts.cuda()==train_labels.cuda().data)
        loss=cirterion(outputs,train_labels.cuda())
        loss.backward()
        optimizer.step()
        loss_+=loss.item()
        #print(f"epoch: {epoch},loss: {loss_}")
        total+=train_labels.size(0)
    print(f"epoch: {epoch},loss={loss_/total*batch_size},acc={100*train_acc/total}%")  
复制代码


在迁移学习中,我们只需要将classifier层调整为我们自己需要的就好,前面的预训练模型不用动,也不用参加训练。

image.png

image.png

测试集上准确率依然有98.6%,也和之前TensorFlow上结果差不多,最后保存模型


torch.save(transfer_model,'./torch_model/transfer_model.pkl')
复制代码


3. 搭建图片分类服务


前面经过不断地调参、优化网络模型、尝试不同方法终于得到了性能优秀的模型,那就得好好利用起来。之前写过FastAPI的专栏,最后用sklearn做了一个demo。今天也和那个类似,使用本地保存下来的模型对上传的图片进行预测分类


# -*- coding: utf8 -*-
from PIL import Image
from fastapi import FastAPI, File, UploadFile, HTTPException
from fastapi.requests import Request
from fastapi.responses import RedirectResponse
from io import BytesIO
import tensorflow as tf
import uvicorn
import numpy as np
from typing import Optional, List
from starlette.templating import Jinja2Templates
tmp = Jinja2Templates(directory='templates')
class Model:
    model: Optional
    def load_model(self):
        self.model = tf.keras.models.load_model("./tf_model/transfer_model")
    def predict(self, input_image):
        output = self.model.predict_classes(input_image).item()
        mapping = {
            0: 'cat',
            1: 'dog'
        }
        return mapping[output]
def read_convert_image(file):
    loaded_image = Image.open(BytesIO(file))
    image_to_convert = np.asarray(loaded_image.resize((224, 224)))[..., :3]
    image_to_convert = np.expand_dims(image_to_convert, 0)
    image_to_convert = image_to_convert / 255.0
    return np.float32(image_to_convert)
describe = '''
<h2>访问/predict/image路由去尝试用训练好的模型对猫狗图片进行分类预测</h2>
'''
app = FastAPI(description=describe)
mymodel = Model()
@app.get("/predict/image")
def index(request: Request):
    return tmp.TemplateResponse('predict.html', {
        'request': request,
    })
@app.post("/predict/image")
async def image(request: Request, image_to_predict: UploadFile = File(...)):
    if image_to_predict is None or image_to_predict.file is None:
        raise HTTPException(status_code=400, detail="Please provide an image when calling this request")
    extension = image_to_predict.filename.split(".")[-1] in ("jpg", "jpeg", "png")
    if not extension:
        raise HTTPException(status_code=400, detail="Please provide an jpg or png image")
    img = image_to_predict.filename
    image_data = read_convert_image(image_to_predict.file.read())
    prediction = mymodel.predict(image_data)
    return tmp.TemplateResponse('result.html', {
        'request': request,
        "img": img,
        'prediction': prediction
    })
@app.get('/')
async def hello():
    return RedirectResponse("/docs")
@app.on_event("startup")
async def startup():
    mymodel.load_model()
if __name__ == "__main__":
    uvicorn.run("app:app", port=8000)
复制代码


依然是启动项目的时候加载模型,然后表单上传图片进行预测,返回结果。不过由于前端确实不好,想用html实现简单的页面渲染但是有的功能还是无法实现很好。无奈,只能做一个简陋的页面出来。


由于模型加载会花费较长时间,所以尽量别添加reload。下次试试TensorFlow serving

result.html


<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>猫狗大战预测</title>
</head>
<body>
<h1>传入图片名称为:{{img}}</h1>
<h1>预测结果为:{{prediction}}</h1>
<a href="/predict/image"><strong>返回继续</strong></a>
</body>
</html>
复制代码

predict.html


<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>猫狗大战预测</title>
</head>
<body>
<h1>上传一个猫/狗图片进行分类预测</h1>
<form action="/predict/image/" enctype="multipart/form-data" onchange="changepic(this)"  method="post">
    <input type="file" id="file" name="image_to_predict" accept="image/*">
    <input type="submit" value="预测">
</form>
<img src="" id="show" width="200">
</body>
<script>
    function changepic() {
        var reads= new FileReader();
        f=document.getElementById('file').files[0];
        reads.readAsDataURL(f);
        reads.onload=function (e) {
            document.getElementById('show').src=this.result;
        };
    }
</script>
</html>
复制代码


4. 最终效果

image.png

image.png


image.png

image.png

image.png

为了检验,去网上下载一些图试试


image.png

image.png

目录
相关文章
|
2月前
|
并行计算 PyTorch TensorFlow
Ubuntu安装笔记(一):安装显卡驱动、cuda/cudnn、Anaconda、Pytorch、Tensorflow、Opencv、Visdom、FFMPEG、卸载一些不必要的预装软件
这篇文章是关于如何在Ubuntu操作系统上安装显卡驱动、CUDA、CUDNN、Anaconda、PyTorch、TensorFlow、OpenCV、FFMPEG以及卸载不必要的预装软件的详细指南。
4993 3
|
3月前
|
数据挖掘 PyTorch TensorFlow
|
2月前
|
PyTorch TensorFlow 算法框架/工具
Jetson环境安装(一):Ubuntu18.04安装pytorch、opencv、onnx、tensorflow、setuptools、pycuda....
本文提供了在Ubuntu 18.04操作系统的NVIDIA Jetson平台上安装深度学习和计算机视觉相关库的详细步骤,包括PyTorch、OpenCV、ONNX、TensorFlow等。
124 1
Jetson环境安装(一):Ubuntu18.04安装pytorch、opencv、onnx、tensorflow、setuptools、pycuda....
|
2月前
|
并行计算 PyTorch TensorFlow
环境安装(一):Anaconda3+pytorch1.6.0+cuda10.0+cudnn7.6.4+tensorflow1.15+pycocotools+pydensecrf
这篇文章详细介绍了如何在Anaconda环境下安装和配置深度学习所需的库和工具,包括PyTorch 1.6.0、CUDA 10.0、cuDNN 7.6.4、TensorFlow 1.15、pycocotools和pydensecrf,并提供了pip国内镜像源信息以及Jupyter Notebook和Anaconda的基本操作。
224 0
环境安装(一):Anaconda3+pytorch1.6.0+cuda10.0+cudnn7.6.4+tensorflow1.15+pycocotools+pydensecrf
|
4月前
|
机器学习/深度学习 PyTorch TensorFlow
conda、anaconda、pip、pytorch、tensorflow有什么关联?
conda、anaconda、pip、pytorch、tensorflow有什么关联?
|
3月前
|
机器学习/深度学习 数据挖掘 TensorFlow
解锁Python数据分析新技能,TensorFlow&PyTorch双引擎驱动深度学习实战盛宴
在数据驱动时代,Python凭借简洁的语法和强大的库支持,成为数据分析与机器学习的首选语言。Pandas和NumPy是Python数据分析的基础,前者提供高效的数据处理工具,后者则支持科学计算。TensorFlow与PyTorch作为深度学习领域的两大框架,助力数据科学家构建复杂神经网络,挖掘数据深层价值。通过Python打下的坚实基础,结合TensorFlow和PyTorch的强大功能,我们能在数据科学领域探索无限可能,解决复杂问题并推动科研进步。
71 0
|
3月前
|
机器学习/深度学习 数据挖掘 TensorFlow
从数据小白到AI专家:Python数据分析与TensorFlow/PyTorch深度学习的蜕变之路
【9月更文挑战第10天】从数据新手成长为AI专家,需先掌握Python基础语法,并学会使用NumPy和Pandas进行数据分析。接着,通过Matplotlib和Seaborn实现数据可视化,最后利用TensorFlow或PyTorch探索深度学习。这一过程涉及从数据清洗、可视化到构建神经网络的多个步骤,每一步都需不断实践与学习。借助Python的强大功能及各类库的支持,你能逐步解锁数据的深层价值。
76 0
|
4月前
|
UED 开发者
哇塞!Uno Platform 数据绑定超全技巧大揭秘!从基础绑定到高级转换,优化性能让你的开发如虎添翼
【8月更文挑战第31天】在开发过程中,数据绑定是连接数据模型与用户界面的关键环节,可实现数据自动更新。Uno Platform 提供了简洁高效的数据绑定方式,使属性变化时 UI 自动同步更新。通过示例展示了基本绑定方法及使用 `Converter` 转换数据的高级技巧,如将年龄转换为格式化字符串。此外,还可利用 `BindingMode.OneTime` 提升性能。掌握这些技巧能显著提高开发效率并优化用户体验。
70 0
|
4月前
|
机器学习/深度学习 PyTorch TensorFlow
深度学习框架之争:全面解析TensorFlow与PyTorch在功能、易用性和适用场景上的比较,帮助你选择最适合项目的框架
【8月更文挑战第31天】在深度学习领域,选择合适的框架至关重要。本文通过开发图像识别系统的案例,对比了TensorFlow和PyTorch两大主流框架。TensorFlow由Google开发,功能强大,支持多种设备,适合大型项目和工业部署;PyTorch则由Facebook推出,强调灵活性和速度,尤其适用于研究和快速原型开发。通过具体示例代码展示各自特点,并分析其适用场景,帮助读者根据项目需求和个人偏好做出明智选择。
104 0
|
2月前
|
算法 PyTorch 算法框架/工具
Pytorch学习笔记(九):Pytorch模型的FLOPs、模型参数量等信息输出(torchstat、thop、ptflops、torchsummary)
本文介绍了如何使用torchstat、thop、ptflops和torchsummary等工具来计算Pytorch模型的FLOPs、模型参数量等信息。
373 2