回到首页 返回首页
回到顶部 回到顶部
返回上一页 返回上一页
best-icon

行空板训练文本模型实现文本分类 简单

头像 志学 2025.05.29 48 9

行空板训练文本模型实现文本分类

 

一、项目背景

        随着人工智能的飞速发展给人们生活带来了太多的便利,万能的大模型各领风骚,个性化的小模型也出现在各个领域,给人们带来不一样的体验和便利。今天我给大家介绍一款我自己编程训练的一款文本分类模型,能够实现传统戏剧和传统技艺的项目名称分类识别。

二、项目简介

        本项目使用摄像头拍照识别传统项目的文字名称,将OCR识别出的文字在部署文本分类模型文件的程序中进行推理验证,识别该名称属于哪一个传统项目。将识别出的内容以文字方式显示在屏幕上,并通过语音合成模块播报出识别出的文字内容。

2d9737521b5401e01dcd8739c3e09cd.jpg

 

三、硬件清单

  1.  

材料清单

四、制作过程

(一)在大语言模型的帮助下实现python编程

1.汇总文本材料传统戏剧的传统项目内容和传统技艺的传统项目内容。

2.编写模型训练程序to_onnx.py:

import pandas as pd
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import classification_report
import joblib
from skl2onnx import convert_sklearn
from skl2onnx.common.data_types import StringTensorType, FloatTensorType
import onnx
from onnx import helper, checker
from onnx.compose import merge_models, add_prefix  # 导入 add_prefix

# 读取文件内容
data = """
京剧:传统戏剧
越剧:传统戏剧
黄梅戏:传统戏剧
评剧:传统戏剧
豫剧:传统戏剧
昆曲:传统戏剧
粤剧:传统戏剧
四平戏:传统戏剧
河北梆子:传统戏剧
平阳花鼓:传统戏剧
秦腔:传统戏剧
川剧:传统戏剧
汉剧:传统戏剧
晋剧:传统戏剧
徽剧:传统戏剧
绍剧:传统戏剧
婺剧:传统戏剧
祁剧:传统戏剧
上党梆子:传统戏剧
山东梆子:传统戏剧
滇剧:传统戏剧
藏戏:传统戏剧
潮剧:传统戏剧
桂剧:传统戏剧
湘剧:传统戏剧
柳子戏:传统戏剧
傩戏:传统戏剧
歌仔戏:传统戏剧
采茶戏:传统戏剧
花鼓戏:传统戏剧
陶瓷制作:传统技艺
刺绣:传统技艺
江西炒饭:传统技艺
木雕:传统技艺
剪纸:传统技艺
竹编:传统技艺
草编:传统技艺
扎染:传统技艺
湘绣:传统技艺
蜡染:传统技艺
风筝制作:传统技艺
糖画制作:传统技艺
面人制作:传统技艺
皮影制作:传统技艺
油纸伞制作:传统技艺
紫砂壶制作:传统技艺
景泰蓝制作:传统技艺
核雕:传统技艺
砖雕:传统技艺
贝雕:传统技艺
牙雕:传统技艺
玉雕:传统技艺
木雕船模制作:传统技艺
绒花制作:传统技艺
瓷板画制作:传统技艺
琉璃烧制:传统技艺
打铁技艺:传统技艺
竹刻:传统技艺
麦秆画制作:传统技艺
内画:传统技艺
银饰制作:传统技艺
"""

# 解析文件内容
lines = data.strip().split('\n')
features = []
labels = []

for line in lines:
   line = line.strip()
   if not line:
       continue
   line = line.replace('"', '')
   if ':' in line:
       feature, label = line.split(':', 1)
       features.append(feature)
       labels.append(label)
   else:
       print(f"警告:跳过无效行 - {line}")

# 创建 DataFrame
df = pd.DataFrame({'text': features, 'label': labels})

# 检查标签分布
print("标签分布:")
print(df['label'].value_counts())

# 如果标签只有一种,抛出错误
if len(df['label'].unique()) < 2:
   raise ValueError("数据中只有一种标签,无法训练分类模型。")

# 准备数据
X = df['text']
y = df['label']

# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# 特征提取:TF-IDF
vectorizer = TfidfVectorizer()
X_train_tfidf = vectorizer.fit_transform(X_train)
X_test_tfidf = vectorizer.transform(X_test)

# 保存 TF-IDF 向量化器
joblib.dump(vectorizer, 'tfidf_vectorizer.joblib')

# 训练模型:逻辑回归
model = LogisticRegression()
model.fit(X_train_tfidf, y_train)

# 预测
y_pred = model.predict(X_test_tfidf)

# 评估
print(classification_report(y_test, y_pred, zero_division=0))

# 转换 TfidfVectorizer 为 ONNX
initial_type = [('input', StringTensorType([None]))]
vectorizer_onnx = convert_sklearn(vectorizer, initial_types=initial_type, target_opset=18)

# 为向量化器的节点添加前缀,避免名称冲突
vectorizer_onnx = add_prefix(vectorizer_onnx, 'vectorizer_')

# 转换 LogisticRegression 为 ONNX
input_dim = X_train_tfidf.shape[1]
initial_type = [('input', FloatTensorType([None, input_dim]))]
model_onnx = convert_sklearn(model, initial_types=initial_type, target_opset=18)

# 为分类器的节点添加前缀,避免名称冲突
model_onnx = add_prefix(model_onnx, 'classifier_')

# 获取输入输出名称
vectorizer_output_name = vectorizer_onnx.graph.output[0].name
model_input_name = model_onnx.graph.input[0].name

# 确保第二个模型的输入名称与第一个模型的输出名称匹配
if vectorizer_output_name != model_input_name:
   # 创建新的输入节点
   new_input = helper.make_tensor_value_info(vectorizer_output_name, 
                                            model_onnx.graph.input[0].type.tensor_type.elem_type, 
                                            shape=[None, input_dim])
   
   # 修改模型图形
   new_model = onnx.ModelProto()
   new_model.CopyFrom(model_onnx)
   del new_model.graph.input[:]
   new_model.graph.input.extend([new_input])
   
   for node in new_model.graph.node:
       if node.input[0] == model_input_name:
           node.input[0] = vectorizer_output_name
   
   model_onnx = new_model

# 合并两个 ONNX 模型
merged_model = merge_models(vectorizer_onnx, model_onnx, 
                          io_map=[(vectorizer_onnx.graph.output[0].name, model_onnx.graph.input[0].name)])

# 检查合并后的模型是否有效
checker.check_model(merged_model)

# 保存合并后的 ONNX 模型
onnx.save(merged_model, '/root/model_opset18.onnx')

print("ONNX 模型合并成功,已保存为 model_opset18.onnx")

 

3.编写模型应用部署程序main31.py:

 

import cv2
import re
from XEdu.hub import Workflow as wf 
from pinpong.board import Board
from pinpong.extension.unihiker import *
from pinpong.libs.dfrobot_speech_synthesis import DFRobot_SpeechSynthesis_I2C
import numpy as np
import os
from PIL import Image, ImageDraw, ImageFont
import tkinter as tk
from tkinter import messagebox
from PIL import ImageTk
import joblib
import onnxruntime  # 引入ONNX Runtime
import pygame  # 引入pygame用于音频播放

# 初始化pygame混音器
pygame.mixer.init()

# 定义模型和向量化器的路径
MODEL_PATH = 'model_opset18.onnx'
VECTORIZER_PATH = 'tfidf_vectorizer.joblib'

try:
   # 使用 ONNX Runtime 加载模型
   model = onnxruntime.InferenceSession(MODEL_PATH)
   # 加载TF-IDF向量化器
   vectorizer = joblib.load(VECTORIZER_PATH)
except FileNotFoundError:
   print(f"文件未找到:确保 '{MODEL_PATH}' 和 '{VECTORIZER_PATH}' 文件与代码位于同一目录下。")
   model, vectorizer = None, None
except Exception as e:
   print(f"加载模型或向量化器时发生错误: {e}")
   import traceback
   traceback.print_exc()
   # 避免后续代码因未定义变量出错
   model, vectorizer = None, None

# 初始化行空板
Board().begin()
p_gravitysynthesis = DFRobot_SpeechSynthesis_I2C()
p_gravitysynthesis.begin(p_gravitysynthesis.V2)

# 打开摄像头
cap = cv2.VideoCapture(0)

if not cap.isOpened():
   print("无法打开摄像头")
   exit()

# 创建 Tkinter 窗口
root = tk.Tk()
root.title("摄像头预览")

# 创建一个标签用于显示摄像头预览
label = tk.Label(root)
label.pack()

# 定义保存并识别函数
def save_and_recognize():
   ret, frame = cap.read()
   if ret:
       # 保存捕获的图像
       cv2.imwrite('captured_image.png', frame)
       print("图像已保存为 captured_image.png")
       # 关闭摄像头和 Tkinter 窗口
       cap.release()
       root.destroy()
       # 图片识别代码中的文本内容
       ocr = wf(task='ocr')
       result, ocr_img = ocr.inference(data='captured_image.png', img_type='cv2')  # 进行模型推理
       ocr_format_result = ocr.format_output(lang="zh")  # 推理结果格式化输出
       print(ocr_format_result)

       # 从输出中提取文本
       texts = re.findall(r"'文本': \['(.*?)'\]", str(ocr_format_result))
       text = " ".join(texts)

       def predict_text_category(text):
           """
           对输入的文本进行分类预测
           :param text: 输入的文本
           :return: 预测的类别
           """
           if model is None:
               print("模型加载失败,无法进行预测。")
               return None
           # ONNX模型推理逻辑
           # 这里直接传递字符串输入到合并后的 ONNX 模型
           input_name = model.get_inputs()[0].name
           output_name = model.get_outputs()[0].name
           # 运行模型推理
           prediction = model.run([output_name], {input_name: [text]})
           return prediction[0]

       # 对识别出的文本进行预测
       category = predict_text_category(text)
       if category is not None:
           # 去掉多余的引号、冒号、方括号
           text = text.replace('"', '').replace(':', '').replace('[', '').replace(']', '')
           category = str(category).replace('"', '').replace(':', '').replace('[', '').replace(']', '').replace("'", "")
           formatted_result = f"{text}属于{category}"
           print(formatted_result)

           # 创建一个黑色背景的图像并设置为150x220
           img = np.zeros((150, 220, 3), np.uint8)
           img_pil = Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
           draw = ImageDraw.Draw(img_pil)
           font = ImageFont.truetype("HYQiHei_50S.ttf", 20)  # 使用黑体字体

           # 在图像上靠左绘制文字
           draw.text((10, 10), formatted_result, font=font, fill=(255, 255, 255))

           # 将PIL图像转换回OpenCV格式
           img = cv2.cvtColor(np.array(img_pil), cv2.COLOR_RGB2BGR)

           # 显示图像
           cv2.imshow('Predicted Category', img)

           # 使用行空板语音合成模块播放语音
           p_gravitysynthesis.speak(formatted_result)

           cv2.waitKey(0)
           cv2.destroyAllWindows()
   else:
       messagebox.showerror("错误", "无法捕获图像")

# 定义退出函数
def exit_preview():
   cap.release()
   root.destroy()

# 创建保存并识别按钮
save_button = tk.Button(root, text="保存并识别", command=save_and_recognize)
save_button.pack()

# 创建退出按钮
exit_button = tk.Button(root, text="退出", command=exit_preview)
exit_button.pack()

# 定义更新预览的函数
def update_preview():
   ret, frame = cap.read()
   if ret:
       # 缩放帧到 220x220
       frame = cv2.resize(frame, (220, 220))
       frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
       img = Image.fromarray(frame)
       img = ImageTk.PhotoImage(image=img)
       label.config(image=img)
       label.image = img
   root.after(10, update_preview)

# 开始更新预览
update_preview()

# 运行 Tkinter 主循环
root.mainloop()

 

(二)将程序上传到行空板

e7e3a08bb26b23f2782c7a3f595b24c.png

将这两个程序文件to_onnx.py,main31.py,上传到行空板。

 

(三)运行to_onnx.py训练出模型文件,这个模型文件要在行空板里训练完成。

1.打开Jupytery页面,找到to_onnx.py并运行。

0a8a6d21edff7873afd923ecac55109.png
9853cb1fb66efdfed05ad77ba968002.png

 

(四)运行主程序文件main31.py验证项目。

(五)调试并安装必要的库文件

如果在运行程序时报错,可根据提示进行相应的调整与补充相关文件,对于不熟练的的操作者可以提前安装下面几个重要的库文件:

290aff4c277041c4b6de255d420da59.png
9ed00ffbe8fb9bc719054d249ac6a0a.png

 

2477684b8a570690600a72439188f65.png

文件存在需要安装的库.ipynb里,打开该文件依次运行就可以了。

 

 

评论

user-avatar
  • robotM

    robotM2025.06.13

    可以图形化编程吗

    0
    • robotM

      robotM2025.06.13

      可以图形化编程吗

      0
      • robotM

        robotM2025.06.13

        可以图形化编程吗

        0
        • robotM

          robotM2025.06.13

          可以图形化编程吗

          0
          • robotM

            robotM2025.06.13

            可以图形化编程吗

            0
            • robotM

              robotM2025.06.13

              可以图形化编程吗

              0
              • robotM

                robotM2025.06.13

                可以图形化编程吗

                0
                • robotM

                  robotM2025.06.13

                  可以图形化编程吗

                  0
                  • robotM

                    robotM2025.06.13

                    可以图形化编程吗

                    0