# TensorFlow+Pytorch识别阿猫阿狗（下）

## 2. Pytorch版

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 载入数据

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

### 2.2 模型构建与训练

base_model=nn.Sequential(
nn.MaxPool2d(kernel_size=3, stride=2),
nn.MaxPool2d(kernel_size=3, stride=2),
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)

epochs=40
lr=1e-4
cirterion=nn.CrossEntropyLoss()
base_model=base_model.cuda()
base_model.train()
loss_=0.
train_acc=0.
total=0.
for epoch in range(epochs):
inputs,train_labels=data
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还是保持现状吧。

def test(model,test_loader):
model.eval()
correct=0
test_predict=[]
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

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()

transfer_model=models.densenet201(pretrained=True)
for param in transfer_model.parameters():
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()
epochs = 10
transfer_model.train()
loss_=0.
train_acc=0.
total=0.
for epoch in range(epochs):
inputs,train_labels=data
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}%")

torch.save(transfer_model,'./torch_model/transfer_model.pkl')

## 3. 搭建图片分类服务

# -*- 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 predict(self, input_image):
output = self.model.predict_classes(input_image).item()
mapping = {
0: 'cat',
1: 'dog'
}
return mapping[output]
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
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():
if __name__ == "__main__":
uvicorn.run("app:app", port=8000)

result.html

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

predict.html

<!DOCTYPE html>
<html lang="en">
<meta charset="UTF-8">
<title>猫狗大战预测</title>
<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() {
f=document.getElementById('file').files[0];
document.getElementById('show').src=this.result;
};
}
</script>
</html>

## 4. 最终效果

|
3月前
|

TensorFlow识别GPU难道就这么难吗？还是我的GPU有问题？
TensorFlow识别GPU难道就这么难吗？还是我的GPU有问题？
49 0
|
3月前
|
TensorFlow 算法框架/工具 异构计算
Windows部署TensorFlow后识别GPU失败，原因是啥？
Windows部署TensorFlow后识别GPU失败，原因是啥？
26 0
|
3月前
|

Tensorflow、Pytorch、
Tensorflow、Pytorch、Horovod、Spark、JupyterLab、TF-Serving、Triton等。 是什么，怎么用，推荐demo
83 40
|
2月前
|

38 0
|
3月前
|

【Python深度学习】Tensorflow对半环形数据分类、手写数字识别、猫狗识别实战（附源码）
【Python深度学习】Tensorflow对半环形数据分类、手写数字识别、猫狗识别实战（附源码）
44 0
|
2月前
|

|
7天前
|

Python中的深度学习：TensorFlow与PyTorch的选择与使用
Python中的深度学习：TensorFlow与PyTorch的选择与使用
10 0
|
2月前
|

TensorFlow vs PyTorch：深度学习框架的比较研究
TensorFlow vs PyTorch：深度学习框架的比较研究
21 1
|
2月前
|

29 2
|
3月前
|

80 1

• 机器翻译
• 工业大脑

更多

更多

更多

更多