# -*- coding: utf-8 -*-
"""
结课项目:人脸识别 + 表情识别 + 颜值打分
环境要求:paddlepaddle-gpu==1.8.5 或 paddlepaddle==1.8.5
"""
import os
import cv2
import numpy as np
import matplotlib.pyplot as plt
from PIL import Image
import paddle
import paddle.fluid as fluid
from paddle.fluid.dygraph import Conv2D, Pool2D, BatchNorm, Linear, Dropout
import random
import json
from tqdm import tqdm
import tarfile
import shutil
"""
百度图片爬虫 - 精简版
爬取20位明星,每人100张图片
"""
import os
import re
import time
import random
import requests
from urllib.parse import quote
# ==================== 配置部分 ====================
CELEBRITIES = [
"刘德华", "周杰伦", "章子怡", "迪丽热巴", "杨幂",
"吴京", "沈腾", "贾玲", "易烊千玺", "王一博",
"赵丽颖", "肖战", "李现", "杨紫", "邓超",
"孙俪", "黄晓明", "杨颖", "胡歌", "刘亦菲"
]
SAVE_DIR = "celebrity_images"
IMAGES_PER_CELEB = 100
# ==================== 爬虫函数 ====================
def crawl_celebrity(name, save_dir, target=100):
"""爬取单个明星的图片"""
print(f"开始: {name}")
# 创建目录
celeb_dir = os.path.join(save_dir, name)
os.makedirs(celeb_dir, exist_ok=True)
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
}
downloaded = 0
page = 0
while downloaded < target and page < 10:
try:
# 构造URL
url = f'http://image.baidu.com/search/flip?tn=baiduimage&word={quote(name)}&pn={page*30}'
# 获取页面
response = requests.get(url, headers=headers, timeout=20)
if response.status_code != 200:
break
# 提取图片URL
img_urls = re.findall(r'"objURL":"(.*?)"', response.text, re.S)
for img_url in img_urls:
if downloaded >= target:
break
try:
# 下载图片
img_data = requests.get(img_url, timeout=25, headers=headers).content
if len(img_data) > 2048: # 有效图片
# 保存
filename = f"{name}_{downloaded:04d}.jpg"
with open(os.path.join(celeb_dir, filename), 'wb') as f:
f.write(img_data)
downloaded += 1
if downloaded % 20 == 0:
print(f" {name}: 已下载 {downloaded}/{target}")
time.sleep(random.uniform(0.1, 0.3))
except:
continue
page += 1
time.sleep(1)
except Exception as e:
print(f" 错误: {e}")
page += 1
continue
print(f"完成: {name} - {downloaded}张")
return downloaded
# ==================== 批量爬取 ====================
def batch_crawl():
"""批量爬取所有明星"""
print(f"目标: {len(CELEBRITIES)}位明星 × {IMAGES_PER_CELEB}张/人")
print(f"保存到: {SAVE_DIR}")
print("="*60)
os.makedirs(SAVE_DIR, exist_ok=True)
total = 0
for i, celeb in enumerate(CELEBRITIES, 1):
print(f"\n[{i}/{len(CELEBRITIES)}] {'='*40}")
count = crawl_celebrity(celeb, SAVE_DIR, IMAGES_PER_CELEB)
total += count
# 明星间延迟
if i < len(CELEBRITIES):
delay = random.uniform(3, 8)
print(f"等待 {delay:.1f}秒...")
time.sleep(delay)
# 显示结果
print(f"\n{'='*60}")
print(f"总计下载: {total} 张图片")
print(f"完成度: {total/(len(CELEBRITIES)*IMAGES_PER_CELEB)*100:.1f}%")
# 检查各目录文件数
print("\n各明星下载数量:")
for celeb in CELEBRITIES:
celeb_dir = os.path.join(SAVE_DIR, celeb)
if os.path.exists(celeb_dir):
files = len([f for f in os.listdir(celeb_dir) if f.endswith('.jpg')])
print(f" {celeb}: {files}张")
return total
# ==================== 运行 ====================
if __name__ == "__main__":
print("百度图片爬虫 - 20位明星每人100张")
print("开始时间:", time.strftime('%Y-%m-%d %H:%M:%S'))
# 直接运行批量爬取
total = batch_crawl()
print(f"\n完成时间: {time.strftime('%Y-%m-%d %H:%M:%S')}")
print(f"图片保存在: {SAVE_DIR}/")
百度图片爬虫 - 20位明星每人100张
开始时间: 2025-12-31 13:04:48
目标: 20位明星 × 100张/人
保存到: celebrity_images
============================================================
[1/20] ========================================
开始: 刘德华
刘德华: 已下载 20/100
刘德华: 已下载 40/100
刘德华: 已下载 60/100
刘德华: 已下载 80/100
刘德华: 已下载 100/100
完成: 刘德华 - 100张
等待 3.5秒...
[2/20] ========================================
开始: 周杰伦
周杰伦: 已下载 20/100
周杰伦: 已下载 40/100
周杰伦: 已下载 60/100
周杰伦: 已下载 80/100
周杰伦: 已下载 100/100
完成: 周杰伦 - 100张
等待 3.5秒...
[3/20] ========================================
开始: 章子怡
章子怡: 已下载 20/100
章子怡: 已下载 40/100
章子怡: 已下载 60/100
章子怡: 已下载 80/100
章子怡: 已下载 100/100
完成: 章子怡 - 100张
等待 3.9秒...
[4/20] ========================================
开始: 迪丽热巴
迪丽热巴: 已下载 20/100
迪丽热巴: 已下载 40/100
迪丽热巴: 已下载 60/100
迪丽热巴: 已下载 80/100
迪丽热巴: 已下载 100/100
完成: 迪丽热巴 - 100张
等待 5.0秒...
[5/20] ========================================
开始: 杨幂
杨幂: 已下载 20/100
杨幂: 已下载 40/100
杨幂: 已下载 60/100
杨幂: 已下载 80/100
杨幂: 已下载 100/100
完成: 杨幂 - 100张
等待 3.5秒...
[6/20] ========================================
开始: 吴京
吴京: 已下载 20/100
吴京: 已下载 40/100
吴京: 已下载 60/100
吴京: 已下载 80/100
吴京: 已下载 100/100
完成: 吴京 - 100张
等待 6.4秒...
[7/20] ========================================
开始: 沈腾
沈腾: 已下载 20/100
沈腾: 已下载 40/100
沈腾: 已下载 60/100
沈腾: 已下载 80/100
沈腾: 已下载 100/100
完成: 沈腾 - 100张
等待 5.8秒...
[8/20] ========================================
开始: 贾玲
贾玲: 已下载 20/100
贾玲: 已下载 40/100
贾玲: 已下载 60/100
贾玲: 已下载 80/100
贾玲: 已下载 100/100
完成: 贾玲 - 100张
等待 7.8秒...
[9/20] ========================================
开始: 易烊千玺
易烊千玺: 已下载 20/100
易烊千玺: 已下载 40/100
易烊千玺: 已下载 60/100
易烊千玺: 已下载 80/100
易烊千玺: 已下载 100/100
完成: 易烊千玺 - 100张
等待 8.0秒...
[10/20] ========================================
开始: 王一博
王一博: 已下载 20/100
王一博: 已下载 40/100
王一博: 已下载 60/100
王一博: 已下载 80/100
王一博: 已下载 100/100
完成: 王一博 - 100张
等待 4.1秒...
[11/20] ========================================
开始: 赵丽颖
赵丽颖: 已下载 20/100
赵丽颖: 已下载 40/100
赵丽颖: 已下载 60/100
赵丽颖: 已下载 80/100
赵丽颖: 已下载 100/100
完成: 赵丽颖 - 100张
等待 5.8秒...
[12/20] ========================================
开始: 肖战
肖战: 已下载 20/100
肖战: 已下载 40/100
肖战: 已下载 60/100
肖战: 已下载 80/100
肖战: 已下载 100/100
完成: 肖战 - 100张
等待 4.3秒...
[13/20] ========================================
开始: 李现
李现: 已下载 20/100
李现: 已下载 40/100
李现: 已下载 60/100
李现: 已下载 80/100
李现: 已下载 100/100
完成: 李现 - 100张
等待 5.5秒...
[14/20] ========================================
开始: 杨紫
杨紫: 已下载 20/100
杨紫: 已下载 40/100
杨紫: 已下载 60/100
杨紫: 已下载 80/100
杨紫: 已下载 100/100
完成: 杨紫 - 100张
等待 6.0秒...
[15/20] ========================================
开始: 邓超
邓超: 已下载 20/100
邓超: 已下载 40/100
邓超: 已下载 60/100
邓超: 已下载 80/100
邓超: 已下载 100/100
完成: 邓超 - 100张
等待 4.8秒...
[16/20] ========================================
开始: 孙俪
孙俪: 已下载 20/100
孙俪: 已下载 40/100
孙俪: 已下载 60/100
孙俪: 已下载 80/100
孙俪: 已下载 100/100
完成: 孙俪 - 100张
等待 6.1秒...
[17/20] ========================================
开始: 黄晓明
黄晓明: 已下载 20/100
黄晓明: 已下载 40/100
黄晓明: 已下载 60/100
黄晓明: 已下载 80/100
黄晓明: 已下载 100/100
完成: 黄晓明 - 100张
等待 3.6秒...
[18/20] ========================================
开始: 杨颖
杨颖: 已下载 20/100
杨颖: 已下载 40/100
杨颖: 已下载 60/100
杨颖: 已下载 80/100
杨颖: 已下载 100/100
完成: 杨颖 - 100张
等待 5.6秒...
[19/20] ========================================
开始: 胡歌
胡歌: 已下载 20/100
胡歌: 已下载 40/100
胡歌: 已下载 60/100
胡歌: 已下载 80/100
胡歌: 已下载 100/100
完成: 胡歌 - 100张
等待 4.7秒...
[20/20] ========================================
开始: 刘亦菲
刘亦菲: 已下载 20/100
刘亦菲: 已下载 40/100
刘亦菲: 已下载 60/100
刘亦菲: 已下载 80/100
刘亦菲: 已下载 100/100
完成: 刘亦菲 - 100张
============================================================
总计下载: 2000 张图片
完成度: 100.0%
各明星下载数量:
刘德华: 100张
周杰伦: 100张
章子怡: 100张
迪丽热巴: 100张
杨幂: 100张
吴京: 100张
沈腾: 100张
贾玲: 100张
易烊千玺: 100张
王一博: 100张
赵丽颖: 100张
肖战: 100张
李现: 100张
杨紫: 100张
邓超: 100张
孙俪: 100张
黄晓明: 100张
杨颖: 100张
胡歌: 100张
刘亦菲: 100张
完成时间: 2025-12-31 13:45:01
图片保存在: celebrity_images/
# 下载并加载 Haar Cascade 文件
haar_cascade_url = "https://raw.githubusercontent.com/opencv/opencv/master/data/haarcascades/haarcascade_frontalface_default.xml"
haar_path = "haarcascade_frontalface_default.xml"
if not os.path.exists(haar_path):
print("下载 Haar cascade...")
import urllib.request
urllib.request.urlretrieve(haar_cascade_url, haar_path)
face_cascade = cv2.CascadeClassifier(haar_path)
def detect_and_crop_face(image_path, target_size=(224, 224)):
"""检测人脸并返回裁剪后的 RGB 图像"""
img = cv2.imread(image_path)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
faces = face_cascade.detectMultiScale(gray, 1.3, 5)
if len(faces) == 0:
return None # 无人脸
x, y, w, h = faces[0] # 取最大人脸
face = img[y:y+h, x:x+w]
face_rgb = cv2.cvtColor(face, cv2.COLOR_BGR2RGB)
face_resized = cv2.resize(face_rgb, target_size)
return face_resized
import os
import cv2
import numpy as np
import random # 修复:必须导入 random
import urllib.request
from PIL import Image
from tqdm import tqdm
import logging
# 配置日志
logging.basicConfig(level=logging.INFO, format='%(levelname)s: %(message)s')
logger = logging.getLogger(__name__)
# =============================
# 初始化人脸检测器
# =============================
haar_path = "haarcascade_frontalface_default.xml"
if not os.path.exists(haar_path):
logger.info("下载 Haar 分类器...")
url = "https://raw.githubusercontent.com/opencv/opencv/master/data/haarcascades/haarcascade_frontalface_default.xml"
try:
urllib.request.urlretrieve(url, haar_path)
logger.info("✅ Haar 分类器下载完成")
except Exception as e:
logger.error(f"❌ 下载失败: {e}")
exit(1)
face_cascade = cv2.CascadeClassifier(haar_path)
if face_cascade.empty():
logger.error("❌ 无法加载 Haar 分类器,请检查文件是否损坏")
exit(1)
def detect_and_crop_face(image_path, target_size=224):
"""
尽可能检测图像中的人脸,返回裁剪后 RGB 格式的标准化图像
支持镜像翻转重试,增加召回率
"""
try:
img = cv2.imread(image_path)
if img is None:
logger.debug(f"⚠️ 图像读取失败: {image_path}")
return None
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 第一次尝试:原图检测(宽松参数)
faces = face_cascade.detectMultiScale(
gray,
scaleFactor=1.1, # 更密集扫描
minNeighbors=3, # 降低阈值
minSize=(30, 30) # 允许小脸
)
if len(faces) == 0:
# 第二次尝试:水平翻转后再检测
flipped_gray = cv2.flip(gray, 1)
faces_flipped = face_cascade.detectMultiScale(
flipped_gray,
scaleFactor=1.1,
minNeighbors=3,
minSize=(30, 30)
)
if len(faces_flipped) == 0:
return None # 真的没找到
# 取第一个,并映射回原坐标
x_f, y_f, w_f, h_f = faces_flipped[0]
original_width = img.shape[1]
x = original_width - x_f - w_f
y, w, h = y_f, w_f, h_f
else:
x, y, w, h = faces[0]
# 扩展边界 10% 防止裁得太紧
pad_w = int(0.1 * w)
pad_h = int(0.1 * h)
x1 = max(0, x - pad_w)
y1 = max(0, y - pad_h)
x2 = min(img.shape[1], x + w + pad_w)
y2 = min(img.shape[0], y + h + pad_h)
face_bgr = img[y1:y2, x1:x2]
face_rgb = cv2.cvtColor(face_bgr, cv2.COLOR_BGR2RGB)
face_resized = cv2.resize(face_rgb, (target_size, target_size))
return face_resized
except Exception as e:
logger.warning(f"⚠️ 处理 {image_path} 时出错: {e}")
return None
def save_cropped(files, folder, celeb_name, phase="train"):
"""
批量处理文件并保存裁剪后的人脸
"""
saved_count = 0
total_count = len(files)
class_dir = os.path.join(folder, celeb_name)
os.makedirs(class_dir, exist_ok=True)
desc = f"{celeb_name} [{phase}]"
for fname in tqdm(files, desc=desc, leave=True):
src_path = os.path.join(ROOT_DIR, celeb_name, fname)
cropped = detect_and_crop_face(src_path)
if cropped is not None:
dst_filename = f"{celeb_name}_{saved_count:04d}.jpg"
dst_path = os.path.join(class_dir, dst_filename)
try:
Image.fromarray(cropped).save(dst_path, quality=95)
saved_count += 1
except Exception as e:
logger.warning(f"⚠️ 保存失败 {dst_path}: {e}")
logger.info(f"✅ {celeb_name} [{phase}]: 保存 {saved_count}/{total_count}")
return saved_count
# =============================
# 主流程配置
# =============================
ROOT_DIR = "celebrity_images"
CROPPED_DIR = "cropped_faces"
TRAIN_DIR = os.path.join(CROPPED_DIR, "train")
TEST_DIR = os.path.join(CROPPED_DIR, "test")
os.makedirs(TRAIN_DIR, exist_ok=True)
os.makedirs(TEST_DIR, exist_ok=True)
celebrities = [
"刘德华", "周杰伦", "章子怡", "迪丽热巴", "杨幂",
"吴京", "沈腾", "贾玲", "易烊千玺", "王一博",
"赵丽颖", "肖战", "李现", "杨紫", "邓超",
"孙俪", "黄晓明", "杨颖", "胡歌", "刘亦菲"
]
# =============================
# 开始处理每个明星
# =============================
if __name__ == "__main__":
logger.info("🚀 开始人脸裁剪任务")
for celeb in celebrities:
celeb_dir = os.path.join(ROOT_DIR, celeb)
if not os.path.exists(celeb_dir):
logger.warning(f"⚠️ 明星目录不存在: {celeb_dir}")
continue
files = [f for f in os.listdir(celeb_dir) if f.lower().endswith(('.jpg', '.jpeg'))]
if len(files) == 0:
logger.warning(f"⚠️ 无有效图片: {celeb}")
continue
# 打乱顺序
random.shuffle(files)
split_idx = int(0.8 * len(files))
train_files = files[:split_idx]
test_files = files[split_idx:]
# 创建子目录
os.makedirs(os.path.join(TRAIN_DIR, celeb), exist_ok=True)
os.makedirs(os.path.join(TEST_DIR, celeb), exist_ok=True)
# 处理训练集和测试集
save_cropped(train_files, TRAIN_DIR, celeb, "train")
save_cropped(test_files, TEST_DIR, celeb, "test")
logger.info("🎉 裁剪完成!所有可用人脸图像已保存至 cropped_faces/")
INFO: 🚀 开始人脸裁剪任务
刘德华 [train]: 100%|██████████| 80/80 [00:25<00:00, 3.08it/s]
INFO: ✅ 刘德华 [train]: 保存 80/80
刘德华 [test]: 100%|██████████| 20/20 [00:06<00:00, 3.33it/s]
INFO: ✅ 刘德华 [test]: 保存 20/20
周杰伦 [train]: 100%|██████████| 80/80 [00:42<00:00, 1.90it/s]
INFO: ✅ 周杰伦 [train]: 保存 75/80
周杰伦 [test]: 100%|██████████| 20/20 [00:15<00:00, 1.32it/s]
INFO: ✅ 周杰伦 [test]: 保存 18/20
章子怡 [train]: 100%|██████████| 80/80 [00:39<00:00, 2.01it/s]
INFO: ✅ 章子怡 [train]: 保存 80/80
章子怡 [test]: 100%|██████████| 20/20 [00:11<00:00, 1.82it/s]
INFO: ✅ 章子怡 [test]: 保存 20/20
迪丽热巴 [train]: 100%|██████████| 80/80 [00:53<00:00, 1.49it/s]
INFO: ✅ 迪丽热巴 [train]: 保存 70/80
迪丽热巴 [test]: 100%|██████████| 20/20 [00:18<00:00, 1.11it/s]
INFO: ✅ 迪丽热巴 [test]: 保存 19/20
杨幂 [train]: 100%|██████████| 80/80 [00:34<00:00, 2.33it/s]
INFO: ✅ 杨幂 [train]: 保存 72/80
杨幂 [test]: 100%|██████████| 20/20 [00:09<00:00, 2.01it/s]
INFO: ✅ 杨幂 [test]: 保存 17/20
吴京 [train]: 100%|██████████| 80/80 [00:26<00:00, 3.01it/s]
INFO: ✅ 吴京 [train]: 保存 77/80
吴京 [test]: 100%|██████████| 20/20 [00:09<00:00, 2.13it/s]
INFO: ✅ 吴京 [test]: 保存 20/20
沈腾 [train]: 100%|██████████| 80/80 [00:39<00:00, 2.04it/s]
INFO: ✅ 沈腾 [train]: 保存 75/80
沈腾 [test]: 100%|██████████| 20/20 [00:04<00:00, 4.48it/s]
INFO: ✅ 沈腾 [test]: 保存 19/20
贾玲 [train]: 100%|██████████| 80/80 [00:37<00:00, 2.11it/s]
INFO: ✅ 贾玲 [train]: 保存 77/80
贾玲 [test]: 100%|██████████| 20/20 [00:13<00:00, 1.51it/s]
INFO: ✅ 贾玲 [test]: 保存 20/20
易烊千玺 [train]: 100%|██████████| 80/80 [00:38<00:00, 2.09it/s]
INFO: ✅ 易烊千玺 [train]: 保存 70/80
易烊千玺 [test]: 100%|██████████| 20/20 [00:11<00:00, 1.68it/s]
INFO: ✅ 易烊千玺 [test]: 保存 19/20
王一博 [train]: 100%|██████████| 80/80 [00:34<00:00, 2.34it/s]
INFO: ✅ 王一博 [train]: 保存 71/80
王一博 [test]: 100%|██████████| 20/20 [00:06<00:00, 3.12it/s]
INFO: ✅ 王一博 [test]: 保存 16/20
赵丽颖 [train]: 100%|██████████| 80/80 [00:46<00:00, 1.73it/s]
INFO: ✅ 赵丽颖 [train]: 保存 80/80
赵丽颖 [test]: 100%|██████████| 20/20 [00:11<00:00, 1.72it/s]
INFO: ✅ 赵丽颖 [test]: 保存 19/20
肖战 [train]: 100%|██████████| 80/80 [00:18<00:00, 4.21it/s]
INFO: ✅ 肖战 [train]: 保存 71/80
肖战 [test]: 100%|██████████| 20/20 [00:07<00:00, 2.75it/s]
INFO: ✅ 肖战 [test]: 保存 17/20
李现 [train]: 100%|██████████| 80/80 [00:36<00:00, 2.21it/s]
INFO: ✅ 李现 [train]: 保存 76/80
李现 [test]: 100%|██████████| 20/20 [00:14<00:00, 1.39it/s]
INFO: ✅ 李现 [test]: 保存 19/20
杨紫 [train]: 100%|██████████| 80/80 [00:48<00:00, 1.66it/s]
INFO: ✅ 杨紫 [train]: 保存 78/80
杨紫 [test]: 100%|██████████| 20/20 [00:14<00:00, 1.35it/s]
INFO: ✅ 杨紫 [test]: 保存 19/20
邓超 [train]: 100%|██████████| 80/80 [00:35<00:00, 2.26it/s]
INFO: ✅ 邓超 [train]: 保存 77/80
邓超 [test]: 100%|██████████| 20/20 [00:05<00:00, 3.44it/s]
INFO: ✅ 邓超 [test]: 保存 19/20
孙俪 [train]: 100%|██████████| 80/80 [00:37<00:00, 2.15it/s]
INFO: ✅ 孙俪 [train]: 保存 80/80
孙俪 [test]: 100%|██████████| 20/20 [00:12<00:00, 1.62it/s]
INFO: ✅ 孙俪 [test]: 保存 20/20
黄晓明 [train]: 100%|██████████| 80/80 [00:37<00:00, 2.11it/s]
INFO: ✅ 黄晓明 [train]: 保存 77/80
黄晓明 [test]: 100%|██████████| 20/20 [00:12<00:00, 1.57it/s]
INFO: ✅ 黄晓明 [test]: 保存 19/20
杨颖 [train]: 100%|██████████| 80/80 [00:50<00:00, 1.57it/s]
INFO: ✅ 杨颖 [train]: 保存 76/80
杨颖 [test]: 100%|██████████| 20/20 [00:12<00:00, 1.59it/s]
INFO: ✅ 杨颖 [test]: 保存 18/20
胡歌 [train]: 100%|██████████| 80/80 [00:29<00:00, 2.69it/s]
INFO: ✅ 胡歌 [train]: 保存 75/80
胡歌 [test]: 100%|██████████| 20/20 [00:11<00:00, 1.68it/s]
INFO: ✅ 胡歌 [test]: 保存 19/20
刘亦菲 [train]: 100%|██████████| 80/80 [00:45<00:00, 1.76it/s]
INFO: ✅ 刘亦菲 [train]: 保存 76/80
刘亦菲 [test]: 100%|██████████| 20/20 [00:18<00:00, 1.07it/s]
INFO: ✅ 刘亦菲 [test]: 保存 18/20
INFO: 🎉 裁剪完成!所有可用人脸图像已保存至 cropped_faces/
class FaceRecognitionNet(fluid.dygraph.Layer):
def __init__(self, num_classes=20):
super(FaceRecognitionNet, self).__init__()
self.conv1 = Conv2D(num_channels=3, num_filters=32, filter_size=3, stride=1, padding=1, act='relu')
self.pool1 = Pool2D(pool_size=2, pool_stride=2, pool_type='max')
self.bn1 = BatchNorm(num_channels=32, act='relu')
self.conv2 = Conv2D(num_channels=32, num_filters=64, filter_size=3, stride=1, padding=1, act='relu')
self.pool2 = Pool2D(pool_size=2, pool_stride=2, pool_type='max')
self.bn2 = BatchNorm(num_channels=64, act='relu')
self.conv3 = Conv2D(num_channels=64, num_filters=128, filter_size=3, stride=1, padding=1, act='relu')
self.pool3 = Pool2D(pool_size=2, pool_stride=2, pool_type='max')
self.bn3 = BatchNorm(num_channels=128, act='relu')
self.fc1 = Linear(input_dim=128*28*28, output_dim=512, act='relu')
self.dropout = Dropout(0.5)
self.fc2 = Linear(input_dim=512, output_dim=num_classes, act='softmax')
def forward(self, x):
x = self.conv1(x)
x = self.bn1(x)
x = self.pool1(x)
x = self.conv2(x)
x = self.bn2(x)
x = self.pool2(x)
x = self.conv3(x)
x = self.bn3(x)
x = self.pool3(x)
x = fluid.layers.flatten(x, axis=1)
x = self.fc1(x)
x = self.dropout(x)
x = self.fc2(x)
return x
# 数据增强和读取
def reader_creator(data_dir, label_dict, mode='train'):
def reader():
for label_name in os.listdir(data_dir):
class_dir = os.path.join(data_dir, label_name)
if not os.path.isdir(class_dir):
continue
label = label_dict[label_name]
for img_name in os.listdir(class_dir):
img_path = os.path.join(class_dir, img_name)
try:
img = Image.open(img_path).convert('RGB').resize((224, 224))
img = np.array(img).astype('float32') / 255.0
if mode == 'train':
# 简单数据增强
if random.random() > 0.5:
img = img[:, ::-1, :] # 水平翻转
yield img.transpose(2, 0, 1), label
except:
continue
return reader
# 创建标签字典
label_dict = {name: idx for idx, name in enumerate(celebrities)}
with fluid.dygraph.guard():
model = FaceRecognitionNet(num_classes=20)
optimizer = fluid.optimizer.AdamOptimizer(learning_rate=0.001, parameter_list=model.parameters())
train_reader = paddle.batch(reader_creator(TRAIN_DIR, label_dict, 'train'), batch_size=32)
test_reader = paddle.batch(reader_creator(TEST_DIR, label_dict, 'test'), batch_size=32)
epochs = 30
best_acc = 0.0
for epoch in range(epochs):
model.train()
total_loss = 0.0
total_acc = 0.0
count = 0
for batch_id, data in enumerate(test_reader()): # ✅ 加了 (),现在可以迭代了
imgs = np.array([x[0] for x in data]).astype('float32')
labels = np.array([[x[1]] for x in data]).astype('int64')
imgs = fluid.dygraph.to_variable(imgs)
labels = fluid.dygraph.to_variable(labels)
logits = model(imgs)
loss = fluid.layers.cross_entropy(logits, labels)
avg_loss = fluid.layers.mean(loss)
acc = fluid.layers.accuracy(logits, labels)
avg_loss.backward()
optimizer.minimize(avg_loss)
model.clear_gradients()
total_loss += avg_loss.numpy()[0]
total_acc += acc.numpy()[0]
count += 1
print(f"Epoch {epoch+1}, Loss: {total_loss/count:.4f}, Acc: {total_acc/count:.4f}")
# 测试阶段
model.eval()
test_acc = 0.0
test_count = 0
for batch_id, data in enumerate(test_reader()): # ← 加上 ()
imgs = np.array([x[0] for x in data]).astype('float32')
labels = np.array([[x[1]] for x in data]).astype('int64')
imgs = fluid.dygraph.to_variable(imgs)
labels = fluid.dygraph.to_variable(labels)
logits = model(imgs)
acc = fluid.layers.accuracy(logits, labels)
test_acc += acc.numpy()[0]
test_count += 1
test_acc /= test_count
print(f"Test Accuracy: {test_acc:.4f}")
if test_acc > best_acc:
best_acc = test_acc
fluid.save_dygraph(model.state_dict(), "face_recognition_model_best")
print(f"✅ 人脸识别模型最高准确率: {best_acc:.4f}")
Epoch 1, Loss: 35.5900, Acc: 0.0052
Test Accuracy: 0.0755
Epoch 2, Loss: 5.3439, Acc: 0.2035
Test Accuracy: 0.1360
Epoch 3, Loss: 3.1714, Acc: 0.2670
Test Accuracy: 0.2659
Epoch 4, Loss: 2.3204, Acc: 0.3503
Test Accuracy: 0.3807
Epoch 5, Loss: 2.0990, Acc: 0.3743
Test Accuracy: 0.5175
Epoch 6, Loss: 1.9403, Acc: 0.4483
Test Accuracy: 0.5964
Epoch 7, Loss: 1.7637, Acc: 0.4608
Test Accuracy: 0.6725
Exception ignored in: <generator object reader_creator.<locals>.reader at 0x7f20ad638b50>
RuntimeError: generator ignored GeneratorExit
---------------------------------------------------------------------------
KeyboardInterrupt Traceback (most recent call last)
/tmp/ipykernel_2136/1186155192.py in <module>
46 labels = fluid.dygraph.to_variable(labels)
47
---> 48 logits = model(imgs)
49 loss = fluid.layers.cross_entropy(logits, labels)
50 avg_loss = fluid.layers.mean(loss)
/opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages/paddle/fluid/dygraph/layers.py in __call__(self, *inputs, **kwargs)
459
460 with param_guard(self._parameters):
--> 461 outputs = self.forward(*inputs, **kwargs)
462
463 for forward_post_hook in self._forward_post_hooks.values():
/tmp/ipykernel_2136/1368681083.py in forward(self, x)
21 x = self.conv1(x)
22 x = self.bn1(x)
---> 23 x = self.pool1(x)
24
25 x = self.conv2(x)
/opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages/paddle/fluid/dygraph/layers.py in __call__(self, *inputs, **kwargs)
459
460 with param_guard(self._parameters):
--> 461 outputs = self.forward(*inputs, **kwargs)
462
463 for forward_post_hook in self._forward_post_hooks.values():
/opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages/paddle/fluid/dygraph/nn.py in forward(self, input)
839 'use_cudnn', self._use_cudnn, 'ceil_mode', self._ceil_mode,
840 'use_mkldnn', False, 'exclusive', self._exclusive)
--> 841 return core.ops.pool2d(input, *attrs)
842
843 check_variable_and_dtype(
KeyboardInterrupt:
# 假设你前面已经运行过 create_dataset_from_directories() 并得到 df
# 如果没有,重新定义一次:
import pandas as pd
import os
def create_dataset_from_directories(base_dir='work'):
emotion_labels = {
0: 'Angry', 1: 'Disgust', 2: 'Fear', 3: 'Happy',
4: 'Sad', 5: 'Surprise', 6: 'Neutral'
}
records = []
dataset_types = ['train', 'val', 'test']
for dataset_type in dataset_types:
dataset_dir = os.path.join(base_dir, dataset_type)
if not os.path.exists(dataset_dir):
print(f"警告: {dataset_dir} 目录不存在")
continue
for emotion_str in os.listdir(dataset_dir):
if emotion_str.isdigit():
emotion = int(emotion_str)
emotion_dir = os.path.join(dataset_dir, emotion_str)
if not os.path.isdir(emotion_dir):
continue
for img_file in os.listdir(emotion_dir):
if img_file.lower().endswith(('.jpg', '.jpeg', '.png')):
img_path = os.path.join(emotion_dir, img_file)
records.append({
'emotion': emotion,
'image_path': img_path,
'dataset_type': dataset_type
})
return pd.DataFrame(records)
# 重建 df(如果你当前环境中还没有)
df = create_dataset_from_directories()
print("数据集形状:", df.shape)
数据集形状: (83571, 3)
class EmotionNet(fluid.dygraph.Layer):
def __init__(self, num_classes=7):
super(EmotionNet, self).__init__()
self.conv1 = Conv2D(3, 64, 7, stride=2, padding=3, act='relu')
self.bn1 = BatchNorm(64, act='relu')
self.pool1 = Pool2D(pool_size=3, pool_stride=2, pool_type='max')
# Block 1
self.conv2a = Conv2D(64, 64, 3, padding=1, act=None)
self.bn2a = BatchNorm(64, act='relu')
self.conv2b = Conv2D(64, 64, 3, padding=1, act=None)
self.bn2b = BatchNorm(64, act=None)
# Block 2
self.conv3a = Conv2D(64, 128, 3, stride=2, padding=1, act=None)
self.bn3a = BatchNorm(128, act='relu')
self.conv3b = Conv2D(128, 128, 3, padding=1, act=None)
self.bn3b = BatchNorm(128, act=None)
self.downsample = Conv2D(64, 128, 1, stride=2, act=None)
# 分类头
self.pool2 = Pool2D(pool_size=7, pool_type='avg')
self.fc = Linear(128, num_classes, act='softmax')
def forward(self, x):
x = self.conv1(x)
x = self.bn1(x)
x = self.pool1(x)
# Block 1
residual = x
out = self.conv2a(x)
out = self.bn2a(out)
out = self.conv2b(out)
out = self.bn2b(out)
out += residual # 残差连接
out = fluid.layers.relu(out)
# Block 2
residual = self.downsample(x)
out = self.conv3a(out)
out = self.bn3a(out)
out = self.conv3b(out)
out = self.bn3b(out)
out += residual
out = fluid.layers.relu(out)
# 全局平均池化 + 分类
out = self.pool2(out)
out = fluid.layers.flatten(out, axis=1)
out = self.fc(out)
return out
with fluid.dygraph.guard():
print("开始训练表情识别模型...")
model = EmotionNet(num_classes=7)
optimizer = fluid.optimizer.AdamOptimizer(
learning_rate=fluid.layers.piecewise_decay(
boundaries=[10000, 20000],
values=[0.001, 0.0005, 0.0001]
),
parameter_list=model.parameters()
)
batch_size = 64
epochs = 30
best_acc = 0.0
for epoch in range(epochs):
model.train()
total_loss = 0.0
total_acc = 0.0
count = 0
# ✅ 使用正确的变量名
idxs = list(range(len(X_train)))
np.random.shuffle(idxs)
for i in tqdm(range(0, len(idxs), batch_size), desc=f"Epoch {epoch+1}/{epochs}"):
batch_idx = idxs[i:i+batch_size]
x_batch = X_train[batch_idx]
y_batch = y_train[batch_idx]
x_tensor = fluid.dygraph.to_variable(x_batch)
y_tensor = fluid.dygraph.to_variable(y_batch)
output = model(x_tensor)
loss = fluid.layers.cross_entropy(output, y_tensor)
avg_loss = fluid.layers.mean(loss)
acc = fluid.layers.accuracy(output, y_tensor)
avg_loss.backward()
optimizer.minimize(avg_loss)
model.clear_gradients()
total_loss += avg_loss.numpy()[0]
total_acc += acc.numpy()[0]
count += 1
if count > 0:
print(f"Train Loss: {total_loss/count:.4f}, Acc: {total_acc/count:.4f}")
else:
print("⚠️ 训练集为空,跳过该轮")
continue
# 验证阶段
model.eval()
val_acc = 0.0
val_count = 0
for i in range(0, len(X_val), batch_size):
x_batch = X_val[i:i+batch_size]
y_batch = y_val[i:i+batch_size]
x_var = fluid.dygraph.to_variable(x_batch)
y_var = fluid.dygraph.to_variable(y_batch)
pred = model(x_var)
acc = fluid.layers.accuracy(pred, y_var)
val_acc += acc.numpy()[0]
val_count += 1
if val_count > 0:
val_acc /= val_count
else:
val_acc = 0.0
print(f"Validation Accuracy: {val_acc:.4f}")
if val_acc > best_acc:
best_acc = val_acc
fluid.save_dygraph(model.state_dict(), "emotion_model_best")
print(f"✅ 新的最佳模型已保存,准确率: {best_acc:.4f}")
print(f"\n🎉 表情识别模型训练完成!最高验证准确率: {best_acc:.4f}")
开始训练表情识别模型...
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
/tmp/ipykernel_2891/30154203.py in <module>
22
23 # ✅ 使用正确的变量名
---> 24 idxs = list(range(len(X_train)))
25 np.random.shuffle(idxs)
26
NameError: name 'X_train' is not defined
with fluid.dygraph.guard():
print("开始训练表情识别模型...")
model = EmotionNet(num_classes=7)
optimizer = fluid.optimizer.AdamOptimizer(
learning_rate=fluid.layers.piecewise_decay(
boundaries=[10000, 20000],
values=[0.001, 0.0005, 0.0001]
),
parameter_list=model.parameters()
)
batch_size = 64
epochs = 30
best_acc = 0.0
for epoch in range(epochs):
model.train()
total_loss = 0.0
total_acc = 0.0
count = 0
# 打乱训练数据
idxs = list(range(len(X_train_3ch)))
np.random.shuffle(idxs)
for i in tqdm(range(0, len(idxs), batch_size), desc=f"Epoch {epoch+1}/{epochs}"):
batch_idx = idxs[i:i+batch_size]
x_batch = X_train_3ch[batch_idx]
y_batch = y_train[batch_idx]
x_tensor = fluid.dygraph.to_variable(x_batch)
y_tensor = fluid.dygraph.to_variable(y_batch)
output = model(x_tensor)
loss = fluid.layers.cross_entropy(output, y_tensor)
avg_loss = fluid.layers.mean(loss)
acc = fluid.layers.accuracy(output, y_tensor)
avg_loss.backward()
optimizer.minimize(avg_loss)
model.clear_gradients()
total_loss += avg_loss.numpy()[0]
total_acc += acc.numpy()[0]
count += 1
print(f"Train Loss: {total_loss/count:.4f}, Acc: {total_acc/count:.4f}")
# 验证阶段
model.eval()
val_acc = 0.0
val_count = 0
for i in range(0, len(X_val_3ch), batch_size):
x_batch = X_val_3ch[i:i+batch_size]
y_batch = y_val[i:i+batch_size]
x_var = fluid.dygraph.to_variable(x_batch)
y_var = fluid.dygraph.to_variable(y_batch)
pred = model(x_var)
acc = fluid.layers.accuracy(pred, y_var)
val_acc += acc.numpy()[0]
val_count += 1
val_acc /= val_count
print(f"Validation Accuracy: {val_acc:.4f}")
# 保存最佳模型
if val_acc > best_acc:
best_acc = val_acc
fluid.save_dygraph(model.state_dict(), "emotion_model_best")
print(f"✅ 新的最佳模型已保存,准确率: {best_acc:.4f}")
print(f"\n🎉 表情识别模型训练完成!最高验证准确率: {best_acc:.4f}")
开始训练表情识别模型...
Epoch 1/30: 0it [00:00, ?it/s]
---------------------------------------------------------------------------
ZeroDivisionError Traceback (most recent call last)
/tmp/ipykernel_99/1490584108.py in <module>
46 count += 1
47
---> 48 print(f"Train Loss: {total_loss/count:.4f}, Acc: {total_acc/count:.4f}")
49
50 # 验证阶段
ZeroDivisionError: float division by zero
# 示例:假设有部分标注文件 scores.json {"image_path": "score"}
scores_data = {
"刘德华_0001.jpg": 8.5,
"迪丽热巴_0002.jpg": 9.2,
# ... 添加更多
}
# 构造数据集(仅作演示)
def create_beauty_dataset():
X_bea, y_bea = [], []
score_dir = os.path.join(CROPPED_DIR, "train") # 使用裁剪后的人脸
for img_file, score in scores_data.items():
celeb = img_file.split('_')[0]
path = os.path.join(score_dir, celeb, img_file)
if os.path.exists(path):
img = Image.open(path).convert('RGB').resize((224, 224))
X_bea.append(np.array(img).astype('float32') / 255.0)
y_bea.append(score)
return np.array(X_bea), np.array(y_bea)
X_bea, y_bea = create_beauty_dataset()
X_bea = X_bea.transpose(0, 3, 1, 2)
# 颜值回归网络
class BeautyNet(fluid.dygraph.Layer):
def __init__(self):
super(BeautyNet, self).__init__()
self.conv1 = Conv2D(3, 32, 3, padding=1, act='relu')
self.pool1 = Pool2D(2, 2, 'max')
self.conv2 = Conv2D(32, 64, 3, padding=1, act='relu')
self.pool2 = Pool2D(2, 2, 'max')
self.fc1 = Linear(64*56*56, 128, act='relu')
self.fc2 = Linear(128, 1, act=None) # 回归输出
def forward(self, x):
x = self.conv1(x)
x = self.pool1(x)
x = self.conv2(x)
x = self.pool2(x)
x = fluid.layers.flatten(x, axis=1)
x = self.fc1(x)
x = self.fc2(x)
return x
# 训练颜值模型(需足够标注数据)
with fluid.dygraph.guard():
model_be = BeautyNet()
opt = fluid.optimizer.AdamOptimizer(0.001, parameter_list=model_be.parameters())
# 这里仅为示意(真实需要更多数据)
if len(X_bea) >= 32:
dataset = [(X_bea[i], y_bea[i]) for i in range(len(X_bea))]
for epoch in range(20):
total_loss = 0.0
for i in range(0, len(dataset), 8):
xb = np.stack([d[0] for d in dataset[i:i+8]], axis=0)
yb = np.array([d[1] for d in dataset[i:i+8]]).reshape(-1, 1).astype('float32')
xb_var = fluid.dygraph.to_variable(xb)
yb_var = fluid.dygraph.to_variable(yb)
pred = model_be(xb_var)
loss = fluid.layers.mse_loss(pred, yb_var)
avg_loss = fluid.layers.mean(loss)
avg_loss.backward()
opt.minimize(avg_loss)
model_be.clear_gradients()
total_loss += avg_loss.numpy()[0]
print(f"Beauty Epoch {epoch+1}, Loss: {total_loss:.4f}")
fluid.save_dygraph(model_be.state_dict(), "beauty_model")
else:
print("⚠️ 标注数据不足,跳过颜值训练")
def inference_pipeline(image_path):
"""输入一张图,输出识别结果"""
# 加载图像
raw_img = Image.open(image_path).convert('RGB')
orig_w, orig_h = raw_img.size
img_array = np.array(raw_img)
# 步骤1:检测人脸
face_img = detect_and_crop_face(image_path)
if face_img is None:
print("未检测到人脸")
return None
face_tensor = np.transpose(face_img, (2, 0, 1)).astype('float32') / 255.0
face_tensor = face_tensor[np.newaxis, ...]
# 加载模型进行推理
with fluid.dygraph.guard():
# --- 人脸识别 ---
model_fr = FaceRecognitionNet(20)
params, _ = fluid.load_dygraph("face_recognition_model_best")
model_fr.load_dict(params)
model_fr.eval()
fr_out = model_fr(fluid.dygraph.to_variable(face_tensor))
fr_pred = np.argmax(fr_out.numpy())
fr_name = [k for k,v in label_dict.items()][fr_pred]
# --- 表情识别 ---
# 注意:需将 RGB 转灰度再复制为三通道
gray_face = cv2.cvtColor(face_img, cv2.COLOR_RGB2GRAY)
gray_3ch = np.stack([gray_face]*3, axis=-1)
gray_3ch = cv2.resize(gray_3ch, (224, 224))
em_tensor = np.transpose(gray_3ch, (2, 0, 1))[np.newaxis, ...].astype('float32') / 255.0
model_em = EmotionNet(7)
params, _ = fluid.load_dygraph("emotion_model_best")
model_em.load_dict(params)
model_em.eval()
em_out = model_em(fluid.dygraph.to_variable(em_tensor))
em_pred = np.argmax(em_out.numpy())
emotion = EMOTION_MAP[em_pred]
# --- 颜值打分 ---
model_be = BeautyNet()
try:
params, _ = fluid.load_dygraph("beauty_model")
model_be.load_dict(params)
model_be.eval()
be_tensor = np.transpose(face_img, (2, 0, 1))[np.newaxis, ...].astype('float32') / 255.0
beauty_score = model_be(fluid.dygraph.to_variable(be_tensor)).numpy()[0][0]
beauty_score = max(0, min(10, beauty_score)) # 截断到 [0,10]
except:
beauty_score = "未知(需更多标注)"
# 绘图显示
fig, ax = plt.subplots(1, 1, figsize=(8, 6))
ax.imshow(img_array)
result_text = f"姓名: {fr_name}\n表情: {emotion}\n颜值: {beauty_score:.2f}" if isinstance(beauty_score, float) else f"姓名: {fr_name}\n表情: {emotion}\n颜值: {beauty_score}"
ax.text(orig_w//2, orig_h - 50, result_text, fontsize=14, bbox=dict(facecolor='yellow', alpha=0.7))
ax.axis('off')
plt.show()
return {
"name": fr_name,
"emotion": emotion,
"beauty_score": beauty_score
}
result = inference_pipeline("celebrity_images/刘德华/刘德华_0001.jpg")
print(result)
请点击此处查看本环境基本用法.
Please click here for more detailed instructions.按文件中的要求将以上代码中的表情识别使用一下示例:
9+
项目大厅>
项目详情
表情分类升级版
0
表情分类,paddle2.2升级版
2022-01-11 15:28:28
AI Studio 经典版
JupyterLab
2.2.2
Python3
版本内容
数据集
Fork记录
评论
当前版本:
第一版
01-11 15:33:51
当前内容阅读耗时约22分钟,试试
小桨总结
实践名称:表情分类
任务:本次识别是一个图像二分类任务,利用卷积神经网络实现图像中表情的分类
实践平台:百度AI实训平台-AI Studio、python3.7+飞桨2.2.1
卷积神经网络(CNN)
卷积神经网络(Convolution Neural Network,简称CNN),CNN 其实可以看作 DNN 的一种特殊形式。它跟传统 DNN 标志性的区别在于两点,Convolution Kernel 以及 Pooling。
数据集介绍
网上公开的人脸表情图像数据集:
包含positive和negative两种表情,共7200余张图片
图片为16464,灰度图像
本次实验中,取其中的10%作为测试集,90%作为训练集
In [1]
# 解压数据集
!cd 'data/data71015' && unzip -q face_data.zip
In [2]
# 导入所需要的库
import os
import pandas as pd
import numpy as np
from PIL import Image
import paddle
import paddle.nn as nn
from paddle.io import Dataset
import paddle.vision.transforms as T
import paddle.nn.functional as F
from paddle.metric import Accuracy
import warnings
warnings.filterwarnings("ignore")
In [3]
all_file_dir = 'data/data71015/face_data'
img_list = []
label_list = []
label_id = 0
class_list = [c for c in os.listdir(all_file_dir) if os.path.isdir(os.path.join(all_file_dir, c))]
for class_dir in class_list:
image_path_pre = os.path.join(all_file_dir, class_dir)
for img in os.listdir(image_path_pre):
img_list.append(os.path.join(image_path_pre, img))
label_list.append(label_id)
label_id += 1
img_df = pd.DataFrame(img_list)
label_df = pd.DataFrame(label_list)
img_df.columns = ['images']
label_df.columns = ['label']
df = pd.concat([img_df, label_df], axis=1)
df = df.reindex(np.random.permutation(df.index))
df.to_csv('face_data.csv', index=0)
In [4]
# 读取数据
df = pd.read_csv('face_data.csv')
image_path_list = df['images'].values
label_list = df['label'].values
# 划分训练集和校验集
all_size = len(image_path_list)
train_size = int(all_size * 0.8)
train_image_path_list = image_path_list[:train_size]
train_label_list = label_list[:train_size]
val_image_path_list = image_path_list[train_size:]
val_label_list = label_list[train_size:]
In [5]
class MyDataset(paddle.io.Dataset):
"""
步骤一:继承paddle.io.Dataset类
"""
def __init__(self, train_img_list, val_img_list,train_label_list,val_label_list, mode='train'):
"""
步骤二:实现构造函数,定义数据读取方式,划分训练和测试数据集
"""
super(MyDataset, self).__init__()
self.img = []
self.label = []
# 借助pandas读csv的库
self.train_images = train_img_list
self.test_images = val_img_list
self.train_label = train_label_list
self.test_label = val_label_list
if mode == 'train':
# 读train_images的数据
for img,la in zip(self.train_images, self.train_label):
self.img.append(img)
self.label.append(la)
else:
# 读test_images的数据
for img,la in zip(self.train_images, self.train_label):
self.img.append(img)
self.label.append(la)
def load_img(self, image_path):
# 实际使用时使用Pillow相关库进行图片读取即可,这里我们对数据先做个模拟
image = Image.open(image_path)
img = image.resize((32, 32), Image.BILINEAR) #Image.BILINEAR双线性插值
img = np.array(img).astype('float32')
#Normalize
img = img / 255 #像素值归一化
return img[np.newaxis, : ,: ]
def __getitem__(self, index):
"""
步骤三:实现__getitem__方法,定义指定index时如何获取数据,并返回单条数据(训练数据,对应的标签)
"""
image = self.load_img(self.img[index])
label = self.label[index]
return image, label
def __len__(self):
"""
步骤四:实现__len__方法,返回数据集总数目
"""
return len(self.img)
In [6]
#train_loader
train_dataset = MyDataset(train_img_list=train_image_path_list, val_img_list=val_image_path_list, train_label_list=train_label_list, val_label_list=val_label_list, mode='train')
train_loader = paddle.io.DataLoader(train_dataset, places=paddle.CPUPlace(), batch_size=32, shuffle=True, num_workers=0)
#val_loader
val_dataset = MyDataset(train_img_list=train_image_path_list, val_img_list=val_image_path_list, train_label_list=train_label_list, val_label_list=val_label_list, mode='test')
val_loader = paddle.io.DataLoader(val_dataset, places=paddle.CPUPlace(), batch_size=32, shuffle=True, num_workers=0)
In [7]
print('=============train dataset=============')
for image, label in train_dataset:
print('image shape: {}, label: {}'.format(image.shape, label))
break
In [8]
#定义网络
class LeNet(nn.Layer):
def __init__(self, num_classes=10):
super(LeNet, self).__init__()
self.num_classes = num_classes
self.features = nn.Sequential(
nn.Conv2D(
1, 6, 3, stride=1, padding=1),
nn.ReLU(),
nn.MaxPool2D(2, 2),
nn.Conv2D(
6, 16, 5, stride=1, padding=0),
nn.ReLU(),
nn.MaxPool2D(2, 2))
if num_classes > 0:
self.fc = nn.Sequential(
nn.Linear(576, 120),
nn.Linear(120, 84), nn.Linear(84, num_classes))
def forward(self, inputs):
x = self.features(inputs)
if self.num_classes > 0:
x = paddle.flatten(x, 1)
x = self.fc(x)
return x
In [9]
# 模型封装
model_le = LeNet(num_classes=2)
model = paddle.Model(model_le)
# 模型可视化
model.summary((1, 1, 32, 32))
In [10]
# 定义优化器
optim = paddle.optimizer.Adam(learning_rate=3e-4, parameters=model.parameters())
# 配置模型
model.prepare(
optim,
paddle.nn.CrossEntropyLoss(soft_label=False),
Accuracy()
)
# 模型训练与评估
model.fit(train_loader,
val_loader,
log_freq=1,
epochs=3,
verbose=1,
)
In [11]
# 保存模型参数
# model.save('Hapi_MyCNN') # save for training
model.save('Hapi_MyCNN1', False) # save for inference
In [12]
import os, time
import matplotlib.pyplot as plt
import paddle
from PIL import Image
import numpy as np
import pandas as pd
def load_image(img_path):
'''
预测图片预处理
'''
img = Image.open(img_path)
plt.imshow(img) #根据数组绘制图像
plt.show()
#resize
img = img.resize((32, 32), Image.BILINEAR) #Image.BILINEAR双线性插值
img = np.array(img).astype('float32')
# HWC to CHW
#Normalize
img = img / 255 #像素值归一化
return img[np.newaxis, : ,: ]
def infer_img(path, model):
'''
模型预测
'''
#对预测图片进行预处理
infer_imgs = []
infer_imgs.append(load_image(path))
infer_imgs = np.array(infer_imgs)
label_pre = []
label_list = ['0:Possitive', '1:Negative']
for i in range(len(infer_imgs)):
data = infer_imgs[i]
dy_x_data = np.array(data).astype('float32')
dy_x_data = dy_x_data[np.newaxis, : ,: ,:]
img = paddle.to_tensor(dy_x_data)
out = model(img)
lab = np.argmax(out.numpy()) #argmax():返回最大数的索引
print("样本: {},被预测为:{}".format(path, label_list[lab]))
return label_pre
if __name__ == '__main__':
use_gpu = True
model_file_path="Hapi_MyCNN1"
paddle.set_device('gpu:0') if use_gpu else paddle.set_device('cpu')
model = paddle.jit.load(model_file_path)
model.eval() #训练模式
infer_img('data/data71015/face_data/Negative/2066.jpg', model)
项目贡献人
AIStudio383107
关注
26.5k
项目热度
5.5k
被Fork数
1
数据集引用
相关项目
查看更多
【Datacapsule】基于文心4.5构建知识图谱的高精度产业级RAG解决方案
自然语言处理
大模型
37.4K
【ERNIE 4.5】ERNIEKit 工业级高性能训练工具快速上手!
自然语言处理
大模型
···
1.7K
【ERNIE-4.5-21B-A3B】让文心开源大模型带你进入哆啦A梦的世界
自然语言处理
大模型
1.0K
文心4.5开源大模型的使用和部署
大模型
718
【新手入门】使用ERNIE-4.5-0.3B-Paddle从原始文本构建知识图谱
自然语言处理
大模型
···
2.2K
助手
最新发布