深度学习之基于CNN实现汉字版手写数字识别(Chinese-Mnist)

本文介绍了使用自建CNN网络实现中文手写数字识别的过程,涉及数据加载、标签处理、模型搭建、训练及混淆矩阵分析。实验结果显示模型在15000张汉字数字图片上达到100%的准确率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Mnist数据集是深度学习入门的数据集,昨天发现了Chinese-Mnist数据集,与Mnist数据集类似,只不过是汉字数字,例如‘一’、‘二’、‘三’等,本次实验利用自己搭建的CNN网络实现Chinese版的手写数字识别。

1.导入库

import tensorflow as tf
import matplotlib.pyplot as plt
import os,PIL,pathlib
import numpy as np
import pandas as pd
import warnings
from tensorflow import keras

warnings.filterwarnings("ignore")#忽略警告信息
plt.rcParams['font.sans-serif'] = ['SimHei']  # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False  # 用来正常显示负号
os.environ['TF_CPP_MIN_LOG_LEVEL']='2'

2.数据加载

原数据中包括15000张图片,如下所示:
在这里插入图片描述
原数据并没有将各类数据分开,而是给出了一个csv文件:
在这里插入图片描述
在进行训练之前将图片分类,首先对数据的标签进行切片

train = pd.read_csv("E:/tmp/.keras/datasets/chinese_mnist/chinese_mnist.csv")
#训练数据的标签
train_image_label = [i for i in train["character"]]
#将标签切片
train_label_ds = tf.data.Dataset.from_tensor_slices(train_image_label)

统计每张图片的具体路径:

#训练数据的具体路径
img_dir = "E:/tmp/.keras/datasets/chinese_mnist/data/data/input"
train_image_paths = []
for row in train.itertuples():
    suite_id = row[1]
    sample_id = row[2]
    code = row[3]
    train_image_paths.append(img_dir+"_"+str(suite_id)+"_"+str(sample_id)+"_"+str(code)+".jpg")
#对图片路径进行切片
train_path_ds = tf.data.Dataset.from_tensor_slices(train_image_paths)

train_image_paths结果如下:

E:/tmp/.keras/datasets/chinese_mnist/data/data/input_1_1_10.jpg

读取图片并进行预处理,然后切片

#图片预处理
def preprocess_image(image):
    image = tf.image.decode_jpeg(image,channels = 3)
    image = tf.image.resize(image,[height,width])
    return image / 255.0
def load_and_preprocess_image(path):
    image = tf.io.read_file(path)
    return preprocess_image(image)
#根据路径读取图片并进行预处理
train_image_ds = train_path_ds.map(load_and_preprocess_image,num_parallel_calls=tf.data.experimental.AUTOTUNE)

将train_image_ds与train_label_ds组合在一起

image_label_ds = tf.data.Dataset.zip((train_image_ds,train_label_ds))

显示图片:

for i in range(20):
    plt.subplot(4, 5, i + 1)
    num +=1
    plt.xticks([])
    plt.yticks([])
    plt.grid(False)

    # 显示图片
    images = plt.imread(train_image_paths[i])
    plt.imshow(images)
    # 显示标签
    plt.xlabel(train_image_label[i])

plt.show()

在并未对数据进行shuffle之前,如下所示:
在这里插入图片描述
原数据中一共15000张图片,分为15类,每类1000张,并按照顺序排列,因此需要对数据进行打乱。

image_label_ds = image_label_ds.shuffle(15000)

按照8:2的比例划分训练集与测试集

train_ds = image_label_ds.take(12000).shuffle(2000)
test_ds = image_label_ds.skip(12000).shuffle(3000)

超参数的设置

height = 64
width = 64
batch_size = 128
epochs = 50

对训练集与测试集进行batch_size 划分

train_ds = train_ds.batch(batch_size)#设置batch_size
train_ds = train_ds.prefetch(buffer_size=tf.data.experimental.AUTOTUNE)
test_ds = test_ds.batch(batch_size)
test_ds = test_ds.prefetch(buffer_size=tf.data.experimental.AUTOTUNE)

再次检查图片,看看是否被打乱顺序:

plt.figure(figsize=(8, 8))

for images, labels in train_ds.take(1):
    # print(images.shape)
    for i in range(12):
        ax = plt.subplot(4, 3, i + 1)
        plt.imshow(images[i])
        plt.title(labels[i].numpy())  # 使用.numpy()将张量转换为 NumPy 数组

        plt.axis("off")
    break
plt.show()

在这里插入图片描述
顺序已被打乱,初始目标完成。

3.网络搭建&&编译

model = tf.keras.Sequential([
    tf.keras.layers.Conv2D(filters=32,kernel_size=(3,3),padding="same",activation="relu",input_shape=[64, 64, 3]),
    tf.keras.layers.MaxPooling2D((2,2)),
    tf.keras.layers.Conv2D(filters=64,kernel_size=(3,3),padding="same",activation="relu"),
    tf.keras.layers.MaxPooling2D((2,2)),
    tf.keras.layers.Conv2D(filters=64,kernel_size=(3,3),padding="same",activation="relu"),
    tf.keras.layers.MaxPooling2D((2,2)),
    tf.keras.layers.Flatten(),
    tf.keras.layers.Dense(64, activation="relu"),
    tf.keras.layers.Dense(15, activation="softmax")
])

model.compile(optimizer="adam",
                loss='sparse_categorical_crossentropy',
                metrics=['accuracy'])
model.summary()
history = model.fit(
    train_ds,
    validation_data=test_ds,
    epochs = epochs
)

经过50次epochs,训练结果如下:
在这里插入图片描述
准确率达到了100%

4.混淆矩阵的绘制

模型加载:

model = tf.keras.models.load_model("E:/Users/yqx/PycharmProjects/chinese_mnist/model.h5")

标签列表如下所示:

all_label_names = ['零','一','二','三','四','五','六','七','八','九','十','百','千','万','亿']

绘制混淆矩阵

from sklearn.metrics import confusion_matrix
import seaborn as sns
import pandas as pd
    # 绘制混淆矩阵
all_label_names = ['零','一','二','三','四','五','六','七','八','九','十','百','千','万','亿']
def plot_cm(labels, pre):
    conf_numpy = confusion_matrix(labels, pre)  # 根据实际值和预测值绘制混淆矩阵
    conf_df = pd.DataFrame(conf_numpy, index=all_label_names,
                               columns=all_label_names)  # 将data和all_label_names制成DataFrame
    plt.figure(figsize=(8, 7))

    sns.heatmap(conf_df, annot=True, fmt="d", cmap="BuPu")  # 将data绘制为混淆矩阵
    plt.title('混淆矩阵', fontsize=15)
    plt.ylabel('真实值', fontsize=14)
    plt.xlabel('预测值', fontsize=14)
    plt.show()

model = tf.keras.models.load_model("E:/Users/yqx/PycharmProjects/chinese_mnist/model.h5")

test_pre = []
test_label = []
for images, labels in test_ds:
    for image, label in zip(images, labels):
        img_array = tf.expand_dims(image, 0)  # 增加一个维度
        pre = model.predict(img_array)  # 预测结果
        test_pre.append(all_label_names[np.argmax(pre)])  # 将预测结果传入列表
        test_label.append(all_label_names[label.numpy()])  # 将真实结果传入列表
plot_cm(test_label, test_pre)  # 绘制混淆矩阵#

在这里插入图片描述
总结:本次实验最复杂的就是标签处理那一块,只有处理好这一步骤,才能正确的将图片和标签划分到一起。实验数据只有15000张,而Mnist数据集有70000张,虽然本次的模型准确率达到了100%,但是仍有可能在别的图片预测错误。

努力加油a啊

好的,让我来逐步回答你的问题: 1. 图片预处理 首先,你需要导入必要的库,如下所示: ```python import pandas as pd import numpy as np import matplotlib.pyplot as plt import cv2 import random from sklearn.model_selection import train_test_split from keras.utils import to_categorical from keras.models import Sequential from keras.layers import Conv2D, MaxPooling2D, Flatten, Dense, Dropout ``` 然后,你需要读取csv文件,并将图片路径和标签提取出来,如下所示: ```python # 读取csv文件 data = pd.read_csv('chinese-mnist.csv') # 提取图片路径和标签 img_paths = data['path'].values labels = data['label'].values ``` 接下来,你需要将图片尺寸调整为150*150,并转换为三通道图片,如下所示: ```python # 将图片尺寸调整为150*150,并转换为三通道图片 def preprocess_img(img_path): img = cv2.imread(img_path) img = cv2.resize(img, (150, 150)) img = cv2.cvtColor(img, cv2.COLOR_GRAY2RGB) return img # 处理所有图片 X = [] for img_path in img_paths: img = preprocess_img('data/' + img_path) X.append(img) X = np.array(X) ``` 最后,你需要将数据集划分为测试集和训练集,其比例为2:8,如下所示: ```python # 将数据集划分为测试集和训练集 X_train, X_test, y_train, y_test = train_test_split(X, labels, test_size=0.2, random_state=42) ``` 2. 创建CNN神经网络模型 接下来,你需要创建一个CNN神经网络模型。这里我们采用了4层卷积层和3层全连接层,如下所示: ```python # 创建CNN神经网络模型 model = Sequential() model.add(Conv2D(32, (3, 3), activation='relu', input_shape=(150, 150, 3))) model.add(MaxPooling2D((2, 2))) model.add(Conv2D(64, (3, 3), activation='relu')) model.add(MaxPooling2D((2, 2))) model.add(Conv2D(128, (3, 3), activation='relu')) model.add(MaxPooling2D((2, 2))) model.add(Conv2D(256, (3, 3), activation='relu')) model.add(MaxPooling2D((2, 2))) model.add(Flatten()) model.add(Dense(512, activation='relu')) model.add(Dropout(0.5)) model.add(Dense(256, activation='relu')) model.add(Dropout(0.5)) model.add(Dense(15, activation='softmax')) ``` 3. 模型编译 接下来,你需要编译模型,包括优化器、loss函数和模型性能。这里我们采用了Adam优化器和交叉熵损失函数,如下所示: ```python # 编译模型 model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy']) ``` 4. 模型训练 接下来,你需要训练模型,包括训练集、展示过程、跑多少轮和精度。这里我们采用了50个epochs,如下所示: ```python # 将标签转换为one-hot编码 y_train = to_categorical(y_train, num_classes=15) y_test = to_categorical(y_test, num_classes=15) # 训练模型 history = model.fit(X_train, y_train, batch_size=32, epochs=50, validation_data=(X_test, y_test)) # 绘制训练过程中的loss和accuracy曲线 plt.plot(history.history['loss'], label='train_loss') plt.plot(history.history['val_loss'], label='val_loss') plt.plot(history.history['accuracy'], label='train_acc') plt.plot(history.history['val_accuracy'], label='val_acc') plt.legend() plt.show() # 在测试集上评估模型精度 test_loss, test_acc = model.evaluate(X_test, y_test) print('Test Accuracy: {:.2f}%'.format(test_acc * 100)) ``` 5. 图像识别 最后,你可以用训练好的模型进行图像识别。你需要将输入的图像预处理成与训练集相同的格式,然后用训练好的模型进行预测,如下所示: ```python # 定义标签 label_dict = { 0: '零', 1: '一', 2: '二', 3: '三', 4: '四', 5: '五', 6: '六', 7: '七', 8: '八', 9: '九', 10: '十', 11: '百', 12: '千', 13: '万', 14: '亿' } # 预处理输入的图像 def preprocess_input(img_path): img = cv2.imread(img_path) img = cv2.resize(img, (150, 150)) img = cv2.cvtColor(img, cv2.COLOR_GRAY2RGB) img = np.expand_dims(img, axis=0) return img # 加载训练好的模型 model = load_model('model.h5') # 进行图像识别 img = preprocess_input('test.png') pred = model.predict(img) pred_label = label_dict[np.argmax(pred)] print('Predicted Label: {}'.format(pred_label)) ``` 这样,你就可以对中文手写数字进行图像识别了。
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

starlet_kiss

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值