CNN卷积神经网络 python代码
·
训练集链接如下,路径需要自行调整
https://download.csdn.net/download/Sr6220033/90164947?spm=1001.2014.3001.5503
1. 训练模型
import os
import numpy as np
from PIL import Image
from sklearn.model_selection import train_test_split
import tensorflow as tf
# 定义数据集路径
train_path = r"C:\Users\HP\Desktop\data\training"
test_path = r"C:\Users\HP\Desktop\data\testing"
# 目标图片尺寸(例如28x28)
img_size = (28, 28)
# 载入数据和标签的函数
def load_data(dataset_path, img_size):
images = []
labels = []
# 遍历每个数字的文件夹
for label in os.listdir(dataset_path):
label_path = os.path.join(dataset_path, label)
if os.path.isdir(label_path): # 如果是文件夹(每个文件夹对应一个数字标签)
for img_name in os.listdir(label_path):
img_path = os.path.join(label_path, img_name)
# 读取图片并调整大小
try:
img = Image.open(img_path).convert('L') # 转换为灰度图
img = img.resize(img_size) # 调整为目标大小
img_array = np.array(img) # 转换为numpy数组
images.append(img_array)
labels.append(int(label)) # 标签是文件夹名,即数字
except Exception as e:
print(f"Error loading image {img_path}: {e}")
# 转换为numpy数组
images = np.array(images)
labels = np.array(labels)
# 标准化处理:将像素值归一化到0-1之间
images = images / 255.0
# 扩展维度:由于图片是二维的(高x宽),我们需要为每张图片添加一个通道维度
images = images.reshape(-1, img_size[0], img_size[1], 1) # (样本数, 高度, 宽度, 通道数)
return images, labels
# 加载训练集和验证集数据
X_train, y_train = load_data(train_path, img_size)
X_test, y_test = load_data(test_path, img_size)
# 划分训练集和验证集(80%训练,20%验证)
X_train, X_val, y_train, y_val = train_test_split(X_train, y_train, test_size=0.2, random_state=42)
# 将标签转换为one-hot编码
y_train = tf.keras.utils.to_categorical(y_train, num_classes=10)
y_val = tf.keras.utils.to_categorical(y_val, num_classes=10)
y_test = tf.keras.utils.to_categorical(y_test, num_classes=10)
# 输出数据形状
print(f"训练集图片形状: {X_train.shape}")
print(f"验证集图片形状: {X_val.shape}")
print(f"测试集图片形状: {X_test.shape}")
print(f"训练集标签形状: {y_train.shape}")
print(f"验证集标签形状: {y_val.shape}")
print(f"测试集标签形状: {y_test.shape}")
# 构建更复杂的神经网络模型(使用卷积神经网络)
model = tf.keras.Sequential([
# 卷积层1
tf.keras.layers.Conv2D(32, (3, 3), activation='relu', input_shape=(28, 28, 1)),
tf.keras.layers.MaxPooling2D((2, 2)),
# 卷积层2
tf.keras.layers.Conv2D(64, (3, 3), activation='relu'),
tf.keras.layers.MaxPooling2D((2, 2)),
# 卷积层3
tf.keras.layers.Conv2D(128, (3, 3), activation='relu'),
tf.keras.layers.MaxPooling2D((2, 2)),
# Flatten层:将二维的卷积输出展平为一维
tf.keras.layers.Flatten(),
# 全连接层
tf.keras.layers.Dense(512, activation='relu'),
tf.keras.layers.Dropout(0.5),
tf.keras.layers.Dense(256, activation='relu'),
tf.keras.layers.Dropout(0.5),
# 输出层
tf.keras.layers.Dense(10, activation='softmax') # 使用softmax激活函数
])
# 编译模型
model.compile(optimizer=tf.keras.optimizers.Adam(learning_rate=0.0001),
loss='categorical_crossentropy', # 使用交叉熵作为误差函数
metrics=['accuracy'])
# 训练模型
model.fit(X_train, y_train, epochs=10, batch_size=32, validation_data=(X_val, y_val))
# 测试模型
test_loss, test_accuracy = model.evaluate(X_test, y_test)
print(f"测试集损失: {test_loss}, 测试集准确率: {test_accuracy}")
# 保存训练好的模型为 .h5 文件
model.save("handwriting_model.h5")
验证模型并创建手写版
import tkinter as tk
import numpy as np
from PIL import Image, ImageDraw
import tensorflow as tf
# 加载已经训练好的模型
model = tf.keras.models.load_model("handwriting_model.h5") # 加载之前训练的模型
# 目标图片尺寸(28x28)
img_size = (28, 28)
# 创建一个Tkinter窗口
root = tk.Tk()
root.title("实时手写数字识别")
# 创建画布,白色背景,黑色笔
canvas = tk.Canvas(root, width=280, height=280, bg="white")
canvas.grid(row=0, column=0)
# 存储绘制的手写图像
image = Image.new("L", (280, 280), color=0) # 创建一个黑色背景的空图像
draw = ImageDraw.Draw(image)
# 鼠标事件处理函数,用来绘制
def draw_line(event):
x1, y1 = (event.x - 2), (event.y - 2)
x2, y2 = (event.x + 2), (event.y + 2)
canvas.create_oval(x1, y1, x2, y2, fill="black", width=10) # 绘制黑色圆点
draw.line([x1, y1, x2, y2], fill=255, width=10) # 在图像上绘制白色线条
canvas.bind("<B1-Motion>", draw_line)
# 清除画布的函数
def clear_canvas():
canvas.delete("all")
global image, draw
image = Image.new("L", (280, 280), color=0) # 重新创建黑色背景的图像
draw = ImageDraw.Draw(image)
# 预测图像的函数
def predict():
# 将绘制的图像缩放为 28x28 并转换为 numpy 数组
img_resized = image.resize(img_size, Image.Resampling.LANCZOS)
img_array = np.array(img_resized) / 255.0 # 归一化
img_array = img_array.reshape(-1, 28, 28, 1) # 适配模型输入形状
# 预测
prediction = model.predict(img_array)
predicted_digit = np.argmax(prediction) # 获取概率最高的标签
# 显示预测结果
result_label.config(text=f"预测结果: {predicted_digit}")
# 创建按钮并显示预测结果
predict_button = tk.Button(root, text="预测", command=predict)
predict_button.grid(row=1, column=0)
# 创建清除按钮
clear_button = tk.Button(root, text="清除", command=clear_canvas)
clear_button.grid(row=2, column=0)
# 创建结果显示标签
result_label = tk.Label(root, text="预测结果: ", font=("Arial", 20))
result_label.grid(row=3, column=0)
# 运行Tkinter事件循环
root.mainloop()
更多推荐
所有评论(0)