Commit ae2380e4 by Leo

upload code

parent c0ebdcd1
data/processed/train_images/
data/processed/train_images/
data/processed/train_images/
data/processed/*.csv
data/models/*.*
src/__pycache__/
src/dataset_generators/__pycache__/
src/models/__pycache__/
src/utils/__pycache__/
src/__pycache__/
data\models\IMAGES_MODEL.pt
data\models\MULTIMODAL_MODEL.pt
data\models\WORD2VEC.model
data\processed\face_images.csv
data\processed\multimodal.csv
data\processed\rest_multimodel.csv
data\processed\rest_text.csv
data\processed\text.csv
\ No newline at end of file
{
{
"python.analysis.typeCheckingMode": "off",
"git.ignoreLimitWarning": true
}
\ No newline at end of file
# 多模态情感分析
# 多模态情感分析
本项目致力于开发一个使用多模态数据(文本和图像)进行情感分析的机器学习模型。
提供了包括:
- 项目概述
- 项目目标
- 环境配置
- 数据
- 模型架构
- 训练
- 结果
## 目录
1. [简介](#简介)
2. [项目目标](#项目目标)
3. [环境配置](#环境配置)
4. [数据](#数据)
5. [模型架构](#模型架构)
6. [训练](#训练)
7. [结果](#结果)
## 简介
欢迎来到多模态情感分析项目!本项目专注于使用多模态数据(如文本、图像和音频)开发情感分析机器学习模型。项目的核心在于注意力融合,我们将注意力机制与融合技术相结合,通过利用多种模态来增强情感分析效果。
传统的情感分析模型通常仅依赖文本,忽略了其他模态的有价值信息。通过注意力融合整合多个模态,我们旨在创建一个更全面和准确的情感分析系统。
注意力融合根据各个模态对情感分析的相关性分配不同的权重或重要性。这使模型能够有选择地关注每个模态中的相关特征,捕获和融合多模态信息。
我们的多模态情感分析模型使用注意力融合结合文本和视觉模态。通过在模型架构中使用注意力机制,模型学会在情感分析过程中关注每个模态最具信息量的方面。这种注意力的融合提高了情感分析性能,并提供了对人类情感的更深入理解。
在本项目中,我们提供了在多模态情感分析中实现注意力融合的详细说明,涵盖了设置过程、模型架构、训练和评估。
## 项目目标
本项目的主要目标包括:
- 开发多模态情感分析模型
- 利用注意力融合技术整合不同模态的信息
- 在多样化数据集上训练模型以增强其泛化能力
- 评估并比较模型与基准方法的性能
## 环境配置
要在本地设置项目,请按以下步骤操作:
1. 安装所需依赖:
- 创建conda环境:
`conda create -y --name ps python=3.9`
- 激活环境:
`conda activate ps`
- 安装环境:
`conda env update -n ps -f environnement.yml`
- 安装项目依赖:
`pip install -r requirements.txt`
2. 运行:
`python main.py`
## 数据
本项目使用T4SA数据集(http://www.t4sa.it/)作为训练和评估的主要数据集。T4SA是一个广受认可的公开数据集,专门为多模态情感分析任务设计。它包含各种模态,包括文本、图像和音频,为训练和测试多模态情感分析模型提供了丰富多样的数据。通过利用T4SA数据集,本项目旨在确保模型在不同情感分析模态和领域中的稳健性和有效性。
## 模型架构
多模态情感分析模型架构包含以下组件:
- 图像模型:提取图像输入的特征
- 文本模型:处理文本输入并生成相应特征
- 注意力机制:计算图像和文本特征的注意力权重
- 融合层:将图像和文本特征组合成融合表示
- 非线性层:使用非线性增强融合特征
- 分类层:将融合特征映射到输出类别数
在前向传播过程中,模型利用注意力融合技术有选择地关注两种模态的相关特征。通过注意力的特征融合增强了模型捕获多模态信息和做出准确情感预测的能力。
通过注意力融合结合文本和视觉线索,模型实现了对情感的更全面理解,超越了传统基于文本的情感分析方法的局限性。
有关模型架构的详细实现,包括层配置和注意力机制,请参考MultimodalModel类中的代码。
![模型架构图1](src/images/m1.png)
![模型架构图2](src/images/m2.png)
## 训练
以下是多模态情感分析模型训练的关键要点:
- **数据加载和分割**:加载数据集后,使用scikit-learn的`train_test_split`将其分为训练和测试子集。测试集大小设为20%,随机状态设为42。
- **训练和测试数据加载**:为训练和测试子集创建数据加载器。训练数据以258的批量大小加载,启用随机打乱,并固定内存以提高训练效率。测试数据加载器使用相同设置。
- **模型初始化**:模型架构包含文本模型和图像模型。文本模型使用指定的类别数(3)初始化,图像模型使用提供的图像形状初始化。这些模型然后组合成`MultimodalModel`的实例。
- **损失函数和优化器初始化**:损失标准设为交叉熵损失。优化器使用Adam,学习率为0.001,用于优化模型参数。
- **模型训练**:使用`utils`模块中的`train`函数开始训练过程。模型训练20个周期,使用`Adam`优化器`torch.optim.Adam()``CrossEntropyLoss`准则`nn.CrossEntropyLoss()`,以及设备(如果可用则使用CUDA,否则使用CPU)。训练过程中会打印训练进度。
## 结果
![准确率图](src/images/fusion-1-acc.PNG)
![准确率曲线图](src/images/fusion-1-accuracy-graph.PNG)
![混淆矩阵](src/images/fusion-1-confusion-matrix.PNG)
name: ps
name: ps
channels:
- pytorch
- nvidia
- conda-forge
- anaconda
- defaults
dependencies:
- abseil-cpp=20211102.0
- altair=4.1.0
- anyio=3.5.0
- argon2-cffi=21.3.0
- argon2-cffi-bindings=21.2.0
- arrow-cpp=11.0.0
- asttokens=2.0.5
- attrs=22.1.0
- aws-c-common=0.4.57
- aws-c-event-stream=0.1.6
- aws-checksums=0.1.9
- aws-sdk-cpp=1.8.185
- babel=2.11.0
- backcall=0.2.0
- beautifulsoup4=4.12.2
- blas=1.0
- bleach=4.1.0
- blinker=1.4
- boost-cpp=1.73.0
- bottleneck=1.3.5
- brotlipy=0.7.0
- bzip2=1.0.8
- c-ares=1.19.0
- ca-certificates=2023.01.10
- certifi=2022.12.7
- cffi=1.15.1
- charset-normalizer=3.1.0
- colorama=0.4.6
- comm=0.1.2
- cryptography=39.0.1
- cuda=11.6.1
- cuda-cccl=11.6.55
- cuda-command-line-tools=11.6.2
- cuda-compiler=11.6.2
- cuda-cudart=11.6.55
- cuda-cudart-dev=11.6.55
- cuda-cuobjdump=11.6.124
- cuda-cupti=11.6.124
- cuda-cuxxfilt=11.6.124
- cuda-libraries=11.6.1
- cuda-libraries-dev=11.6.1
- cuda-memcheck=11.8.86
- cuda-nsight-compute=12.1.1
- cuda-nvcc=11.6.124
- cuda-nvdisasm=12.1.105
- cuda-nvml-dev=11.6.55
- cuda-nvprof=12.1.105
- cuda-nvprune=11.6.124
- cuda-nvrtc=11.6.124
- cuda-nvrtc-dev=11.6.124
- cuda-nvtx=11.6.124
- cuda-nvvp=12.1.105
- cuda-runtime=11.6.1
- cuda-sanitizer-api=12.1.105
- cuda-toolkit=11.6.1
- cuda-tools=11.6.1
- cuda-visual-tools=11.6.1
- debugpy=1.5.1
- decorator=5.1.1
- defusedxml=0.7.1
- eigen=3.4.0
- entrypoints=0.4
- executing=0.8.3
- ffmpeg=4.2.3
- freetype=2.12.1
- gflags=2.2.2
- giflib=5.2.1
- gitdb=4.0.7
- gitpython=3.1.30
- glib=2.69.1
- glog=0.5.0
- gst-plugins-base=1.18.5
- gstreamer=1.18.5
- hdf5=1.10.6
- icu=58.2
- idna=3.4
- importlib_metadata=6.0.0
- intel-openmp=2023.1.0
- ipykernel=6.19.2
- ipython=8.12.0
- ipython_genutils=0.2.0
- ipywidgets=8.0.4
- jedi=0.18.1
- jinja2=3.1.2
- jpeg=9e
- json5=0.9.6
- jsonschema=4.17.3
- jupyter=1.0.0
- jupyter_client=8.1.0
- jupyter_console=6.6.3
- jupyter_core=5.3.0
- jupyter_server=1.23.4
- jupyterlab=3.5.3
- jupyterlab_pygments=0.1.2
- jupyterlab_server=2.22.0
- jupyterlab_widgets=3.0.5
- lerc=3.0
- libboost=1.73.0
- libbrotlicommon=1.0.9
- libbrotlidec=1.0.9
- libbrotlienc=1.0.9
- libcublas=11.9.2.110
- libcublas-dev=11.9.2.110
- libcufft=10.7.1.112
- libcufft-dev=10.7.1.112
- libcurand=10.3.2.106
- libcurand-dev=10.3.2.106
- libcurl=7.88.1
- libcusolver=11.3.4.124
- libcusolver-dev=11.3.4.124
- libcusparse=11.7.2.124
- libcusparse-dev=11.7.2.124
- libdeflate=1.17
- libffi=3.4.2
- libiconv=1.17
- libllvm14=14.0.6
- libnpp=11.6.3.124
- libnpp-dev=11.6.3.124
- libnvjpeg=11.6.2.124
- libnvjpeg-dev=11.6.2.124
- libogg=1.3.4
- libpng=1.6.39
- libprotobuf=3.20.3
- libsodium=1.0.18
- libssh2=1.10.0
- libthrift=0.15.0
- libtiff=4.5.0
- libuv=1.44.2
- libvorbis=1.3.7
- libwebp=1.2.4
- libwebp-base=1.2.4
- libxml2=2.10.3
- libxslt=1.1.37
- llvmlite=0.40.0
- lxml=4.9.2
- lz4-c=1.9.4
- markdown-it-py=2.2.0
- matplotlib-inline=0.1.6
- mdurl=0.1.0
- menuinst=1.4.19
- mistune=0.8.4
- mkl=2023.1.0
- mkl-service=2.4.0
- mkl_fft=1.3.6
- mkl_random=1.2.2
- nbclassic=0.5.5
- nbclient=0.5.13
- nbconvert=6.5.4
- nbformat=5.7.0
- nest-asyncio=1.5.6
- notebook=6.5.4
- notebook-shim=0.2.2
- nsight-compute=2023.1.1.4
- numba=0.57.0
- numexpr=2.8.4
- numpy=1.24.3
- numpy-base=1.24.3
- opencv=4.6.0
- openssl=1.1.1t
- orc=1.7.4
- packaging=23.0
- pandocfilters=1.5.0
- parso=0.8.3
- pcre=8.45
- pickleshare=0.7.5
- pip=23.0.1
- platformdirs=2.5.2
- ply=3.11
- prometheus_client=0.14.1
- prompt-toolkit=3.0.36
- prompt_toolkit=3.0.36
- psutil=5.9.0
- pure_eval=0.2.2
- pyarrow=11.0.0
- pycparser=2.21
- pydeck=0.7.1
- pygments=2.15.1
- pympler=0.9
- pyopenssl=23.0.0
- pyqt=5.15.7
- pyqt5-sip=12.11.0
- pyrsistent=0.18.0
- pysocks=1.7.1
- python=3.9.16
- python-dateutil=2.8.2
- python-fastjsonschema=2.16.2
- pytorch=1.13.1
- pytorch-cuda=11.6
- pytorch-mutex=1.0
- pywin32=305
- pywinpty=2.0.10
- pyyaml=6.0
- pyzmq=25.0.2
- qt-main=5.15.2
- qt-webengine=5.15.9
- qtconsole=5.4.2
- qtpy=2.2.0
- qtwebkit=5.212
- re2=2022.04.01
- rich=13.3.5
- semver=2.13.0
- send2trash=1.8.0
- setuptools=67.8.0
- sip=6.6.2
- six=1.16.0
- smmap=4.0.0
- snappy=1.1.9
- sniffio=1.2.0
- soupsieve=2.4
- sqlite=3.41.2
- stack_data=0.2.0
- streamlit=1.16.0
- tbb=2021.8.0
- terminado=0.17.1
- tinycss2=1.2.1
- tk=8.6.12
- toml=0.10.2
- tomli=2.0.1
- toolz=0.12.0
- torchtext=0.6.0
- tornado=6.2
- tqdm=4.65.0
- traitlets=5.7.1
- typing_extensions=4.5.0
- tzlocal=2.1
- utf8proc=2.6.1
- validators=0.18.2
- vc=14.2
- vs2015_runtime=14.27.29016
- watchdog=2.1.6
- wcwidth=0.2.5
- webencodings=0.5.1
- websocket-client=0.58.0
- wheel=0.38.4
- widgetsnbextension=4.0.5
- win_inet_pton=1.1.0
- winpty=0.4.3
- xz=5.4.2
- yaml=0.2.5
- zeromq=4.3.4
- zlib=1.2.13
- zstd=1.5.5
\ No newline at end of file
# 导入必要的库
# 导入必要的库
import base64
from src.models import MultimodalModel, ImageModel, TextModel # 导入自定义的模型类
import src.utils as ut # 导入工具函数
import torch
from gensim.models import Word2Vec # 用于文本词向量处理
from PIL import Image # 用于图像处理
from flask import Flask, request # Web服务框架
from flask_cors import CORS # 处理跨域请求
import json
from io import BytesIO # 用于处理二进制流数据
# 设置设备(如果有GPU则使用GPU,否则使用CPU)
DEVICE = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')
# 加载预训练的词向量模型
word2vec = Word2Vec.load("./data/models/WORD2VEC.model")
# 以下是文本模型相关代码(当前已注释)
# text_model = TextModel(3).to(DEVICE) # 初始化文本模型,3表示三分类
# text_model.load_state_dict(torch.load("data/models/RETRAINED_TEXT_MODEL.pt")) # 加载预训练权重
# 以下是多模态模型相关代码(当前已注释)
# multimodal_model = MultimodalModel(TextModel(3, True).to(DEVICE), ImageModel(3, 224, True), 3).to(DEVICE)
# multimodal_model.load_state_dict(torch.load("data/models/MULTIMODAL_MODEL.pt"))
# 文本模型预测测试代码(当前已注释)
# print("Text model prediction")
# prediction = ut.predict(model=text_model, device=DEVICE, text="", word2vec_model=word2vec, image=None, IMG_SHAPE=None)
# print(prediction)
# 加载测试图像并初始化图像模型
image = Image.open('c:/Users/bc/Downloads/image.jpg').convert("RGB") # 打开图像并转换为RGB格式
image_model = ImageModel(3, 48).to(DEVICE) # 初始化图像模型,参数:类别数=3,图像尺寸=48
image_model.load_state_dict(torch.load("data/models/IMAGES_MODEL.pt")) # 加载预训练的图像模型权重
# 使用图像模型进行预测
print("Image model prediction")
prediction = ut.predict(model=image_model, device=DEVICE, text=None, word2vec_model=None, image=image, IMG_SHAPE=48)
print(prediction)
# 以下是Flask Web服务相关代码(当前已注释)
# 初始化Flask应用
# app = Flask(__name__)
# 文本分析接口
# @app.route("/text", methods=['POST'])
# def text_analysis():
# json_data = request.data.decode('utf-8') # 解码接收到的JSON数据
# data = json.loads(json_data)
# text = data.get('text') # 获取文本内容
# # 使用文本模型进行预测
# prediction = ut.predict(model=text_model, device=DEVICE, text=text, word2vec_model=word2vec, image=None, IMG_SHAPE=None)
# prediction = prediction[0][0].cpu().numpy() # 将预测结果转换为numpy数组
# # 构造返回结果
# value = {'negative': str(prediction[0]), 'neutral': str(prediction[1]), 'positive': str(prediction[2])}
# return {'response': value}
# 图像分析接口
# @app.route("/image", methods=['POST'])
# def image_analysis():
# json_data = request.data.decode('utf-8')
# data = json.loads(json_data)
# image = data.get('image') # 获取base64编码的图像数据
#
# # 解码base64图像数据
# decoded_file = base64.b64decode(image)
# image = Image.open(BytesIO(decoded_file)).convert('RGB')
#
# # 使用图像模型进行预测
# prediction = ut.predict(model=image_model, device=DEVICE, text=None, word2vec_model=None, image=image, IMG_SHAPE=48)
# prediction = prediction[0][0].cpu().numpy()
# value = {'negative': str(prediction[0]), 'neutral': str(prediction[1]), 'positive': str(prediction[2])}
# return {'response': value}
# 多模态分析接口
# @app.route("/multimodal", methods=['POST'])
# def multimodal_analysis():
# json_data = request.data.decode('utf-8')
# data = json.loads(json_data)
# # 处理图像数据
# image = data.get('image')
# decoded_file = base64.b64decode(image)
# image = Image.open(BytesIO(decoded_file)).convert('RGB')
# # 获取文本数据
# text = data.get('text')
# # 使用多模态模型进行预测
# prediction = ut.predict(model=multimodal_model, device=DEVICE, text=text, word2vec_model=word2vec, image=image, IMG_SHAPE=224)
# prediction = prediction[0].cpu().numpy()
# value = {'negative': str(prediction[0]), 'neutral': str(prediction[1]), 'positive': str(prediction[2])}
# return {'response': value}
# 启动Flask应用
# if __name__ == "__main__":
# app.run(host='127.0.0.1') # 在本地主机上运行服务
# print("test")
\ No newline at end of file
digraph {
digraph {
graph [size="12,12"]
node [align=left fontname=monospace fontsize=10 height=0.2 ranksep=0.1 shape=box style=filled]
1309162144384 [label="
(1, 512)" fillcolor=darkolivegreen1]
1309159449520 [label=ReluBackward0]
1309162075712 -> 1309159449520
1309162075712 [label=AddmmBackward0]
1309155392576 -> 1309162075712
1309028019856 [label="fc1.bias
(512)" fillcolor=lightblue]
1309028019856 -> 1309155392576
1309155392576 [label=AccumulateGrad]
1309162075616 -> 1309162075712
1309162075616 [label=ViewBackward0]
1309162076048 -> 1309162075616
1309162076048 [label=MaxPool2DWithIndicesBackward0]
1309162076096 -> 1309162076048
1309162076096 [label=ReluBackward0]
1309162076192 -> 1309162076096
1309162076192 [label=ConvolutionBackward0]
1309162076288 -> 1309162076192
1309162076288 [label=MaxPool2DWithIndicesBackward0]
1309162076480 -> 1309162076288
1309162076480 [label=ReluBackward0]
1309162076576 -> 1309162076480
1309162076576 [label=ConvolutionBackward0]
1309162076672 -> 1309162076576
1309162076672 [label=MaxPool2DWithIndicesBackward0]
1309162076864 -> 1309162076672
1309162076864 [label=ReluBackward0]
1309162076960 -> 1309162076864
1309162076960 [label=ConvolutionBackward0]
1309162077056 -> 1309162076960
1309162077056 [label=MaxPool2DWithIndicesBackward0]
1309162077248 -> 1309162077056
1309162077248 [label=ReluBackward0]
1309162077344 -> 1309162077248
1309162077344 [label=ConvolutionBackward0]
1309162077440 -> 1309162077344
1309028020976 [label="conv1.weight
(16, 3, 3, 3)" fillcolor=lightblue]
1309028020976 -> 1309162077440
1309162077440 [label=AccumulateGrad]
1309162077392 -> 1309162077344
1309028020816 [label="conv1.bias
(16)" fillcolor=lightblue]
1309028020816 -> 1309162077392
1309162077392 [label=AccumulateGrad]
1309162077008 -> 1309162076960
1309028020576 [label="conv2.weight
(32, 16, 3, 3)" fillcolor=lightblue]
1309028020576 -> 1309162077008
1309162077008 [label=AccumulateGrad]
1309162076768 -> 1309162076960
1309028020496 [label="conv2.bias
(32)" fillcolor=lightblue]
1309028020496 -> 1309162076768
1309162076768 [label=AccumulateGrad]
1309162076624 -> 1309162076576
1309028020096 [label="conv3.weight
(64, 32, 3, 3)" fillcolor=lightblue]
1309028020096 -> 1309162076624
1309162076624 [label=AccumulateGrad]
1309162076384 -> 1309162076576
1309028019936 [label="conv3.bias
(64)" fillcolor=lightblue]
1309028019936 -> 1309162076384
1309162076384 [label=AccumulateGrad]
1309162076240 -> 1309162076192
1309028019776 [label="conv4.weight
(128, 64, 3, 3)" fillcolor=lightblue]
1309028019776 -> 1309162076240
1309162076240 [label=AccumulateGrad]
1309162076000 -> 1309162076192
1309028019616 [label="conv4.bias
(128)" fillcolor=lightblue]
1309028019616 -> 1309162076000
1309162076000 [label=AccumulateGrad]
1309162075760 -> 1309162075712
1309162075760 [label=TBackward0]
1309162076144 -> 1309162075760
1309151309536 [label="fc1.weight
(512, 25088)" fillcolor=lightblue]
1309151309536 -> 1309162076144
1309162076144 [label=AccumulateGrad]
1309159449520 -> 1309162144384
rankdir=TB
}
contourpy
contourpy
gensim
keras
keras-preprocessing
matplotlib
nltk
opencv-contrib-python
pandas
pillow
pydot
scikit-learn
scipy
seaborn
tensorflow==2.10.1
torchaudio
torchdata
pillow
torchvision==0.14.1
torchviz==0.0.2
from .image_dataset import ImageDataset
from .image_dataset import ImageDataset
from .text_dataset import TextDataset
from .multi_modal_dataset import MultimodalDataset
"""
"""
本文件实现了一个用于图像情感分析的数据集加载器。主要功能包括:
1. 从CSV文件中读取图像路径和标签信息
2. 加载并预处理图像数据(调整大小、标准化等)
3. 为深度学习模型提供批量数据加载功能
4. 支持数据集的迭代访问和长度查询
关键特性:
- 支持自定义图像大小
- 使用标准化预处理
- 支持RGB图像处理
- 可配置图像和标签列名
"""
# 导入必要的库
import pandas as pd # 用于读取和处理CSV数据
from torch.utils.data import Dataset # PyTorch数据集基类
import torchvision.transforms as transforms # 图像转换工具
from PIL import Image # 图像处理库
import os # 文件路径处理
# 获取当前文件所在目录
dir = os.path.dirname(__file__)
# 设置CSV文件路径(包含图像信息和标签)
csv_file_path = os.path.join(dir, '..', '..', 'data', 'processed', 'train_images.csv')
# 设置图像文件夹路径
image_path_prefix = os.path.join(dir, '..', '..', 'data', 'processed', 'train_images', 't4sa', '')
class ImageDataset(Dataset):
"""
图像数据集类,继承自PyTorch的Dataset类
用于加载和预处理图像数据,为模型训练提供数据接口
"""
def __init__(self, IMG_SHAPE, IMAGE_COL, LABEL_COL):
"""
初始化数据集
参数:
IMG_SHAPE (int): 目标图像尺寸(将图像调整为IMG_SHAPE x IMG_SHAPE)
IMAGE_COL (str): CSV文件中存储图像路径的列名
LABEL_COL (str): CSV文件中存储标签的列名
"""
self.IMG_SHAPE = IMG_SHAPE
self.IMAGE_COL = IMAGE_COL
self.LABEL_COL = LABEL_COL
# 读取CSV文件,限制读取前10000行数据
self.data = pd.read_csv(csv_file_path).head(10000)
# 定义图像转换流程
# 1. 转换为张量
# 2. 使用ImageNet预训练模型的标准化参数进行标准化
self.transform = transforms.Compose([
transforms.ToTensor(),
transforms.Normalize(mean=[0.485, 0.456, 0.406],
std=[0.229, 0.224, 0.225])
])
def __len__(self):
"""
返回数据集中的样本数量
"""
return len(self.data)
def __getitem__(self, idx):
"""
获取指定索引的数据样本
参数:
idx (int): 样本索引
返回:
tuple: (处理后的图像张量, 对应的标签)
"""
# 获取图像路径并处理路径格式
image_path = self.data.loc[idx, self.IMAGE_COL][1:].split('/')[-1]
# 加载图像并转换为RGB格式
image = Image.open(os.path.join(dir, image_path_prefix, image_path)).convert('RGB')
# 调整图像大小
image = image.resize((self.IMG_SHAPE, self.IMG_SHAPE))
# 应用图像转换(张量化和标准化)
image = self.transform(image)
# 获取对应的标签
label = self.data.loc[idx, self.LABEL_COL]
return image, label
# 以下是被注释掉的模型架构可视化方法
# def plot_model_archi(graphviz_path):
# os.environ["PATH"] += os.pathsep + graphviz_path
# data = ImageDataset(LABELS_DATA_PATH)
# indices = np.arange(len(data))
# train_indices, _ = train_test_split(indices, test_size=0.2, random_state=42)
# train_data = Subset(data, train_indices)
# train_loader = DataLoader(train_data, batch_size=10, shuffle=True)
# model = ImageClassifier().to(DEVICE)
# criterion = nn.CrossEntropyLoss()
# optimizer = torch.optim.Adam(model.parameters(), lr=LR)
# text, _ = next(iter(train_loader))
# output = model(text.to(DEVICE))
# make_dot(output, params=dict(model.named_parameters()))
\ No newline at end of file
"""
"""
文件功能说明:
本文件实现了一个用于多模态情感分析的数据集加载器,集成了文本和图像两种模态。主要功能包括:
1. 同时处理文本和图像数据的加载和预处理
2. 使用Word2Vec模型进行文本的词向量转换
3. 对图像进行标准化处理(调整大小、归一化等)
4. 确保文本序列长度统一(填充或截断)
5. 为深度学习模型提供多模态数据的批量加载功能
关键特性:
- 支持同时处理文本和图像数据
- 使用预训练的Word2Vec模型处理文本
- 图像预处理包含调整大小和标准化
- 支持自定义图像尺寸和序列长度
- 提供标准化的数据加载接口
"""
# 导入必要的库
import pandas as pd # 数据处理库
from torch.utils.data import Dataset # PyTorch数据集基类
import torchvision.transforms as transforms # 图像转换工具
from PIL import Image # 图像处理库
import os # 文件路径处理
from nltk.tokenize import word_tokenize # 文本分词工具
from gensim.models import Word2Vec # 词向量模型
import torch # PyTorch深度学习框架
# 设置文件路径
dir = os.path.dirname(__file__) # 获取当前文件所在目录
csv_file_path = os.path.join(dir, '..', '..', 'data', 'processed', 'multimodal.csv') # 多模态数据CSV文件路径
image_path_prefix = os.path.join("C:/Users/MourtadaHouari/Desktop/ps/mvsa/train_imagesuu/images") # 图像文件夹路径
word2vec_path = os.path.join(dir, '..', '..', 'data', 'models', 'WORD2VEC.model') # Word2Vec模型路径
class MultimodalDataset(Dataset):
"""
多模态数据集类,继承自PyTorch的Dataset类
用于同时加载和预处理文本与图像数据
"""
def __init__(self, IMAGE_SHAPE, TEXT_COL, IMAGE_COL, LABEL_COL):
"""
初始化数据集
参数:
IMAGE_SHAPE (int): 目标图像尺寸
TEXT_COL (str): CSV文件中存储文本内容的列名
IMAGE_COL (str): CSV文件中存储图像路径的列名
LABEL_COL (str): CSV文件中存储标签的列名
"""
# 定义图像转换流程
self.transform = transforms.Compose([
transforms.Resize((IMAGE_SHAPE, IMAGE_SHAPE)), # 调整图像大小
transforms.ToTensor(), # 转换为张量
transforms.Normalize(mean=[0.485, 0.456, 0.406], # 使用ImageNet预训练模型的标准化参数
std=[0.229, 0.224, 0.225])
])
# 保存参数
self.IMG_SHAPE = IMAGE_SHAPE
self.IMAGE_COL = IMAGE_COL
self.LABEL_COL = LABEL_COL
self.TEXT_COL = TEXT_COL
# 加载数据和模型
self.dataframe = pd.read_csv(csv_file_path) # 读取CSV数据
self.word2vec_model = Word2Vec.load(word2vec_path) # 加载词向量模型
self.SEQUENCE_LENGTH = 100 # 设置文本序列最大长度
# 预处理所有文本数据
self.preprocessed_sequences = self._preprocess_text()
def _preprocess_text(self):
"""
预处理所有文本数据
功能:
1. 对文本进行分词
2. 将词转换为词向量索引
3. 对序列进行填充或截断处理
返回:
list: 处理后的文本序列列表
"""
preprocessed_sequences = []
for idx in range(len(self.dataframe)):
# 获取文本内容并进行分词
text = self.dataframe.loc[idx, self.TEXT_COL]
tokens = word_tokenize(text)
# 将词转换为词向量索引
sequence_indices = [self.word2vec_model.wv.key_to_index[word]
for word in tokens
if word in self.word2vec_model.wv]
# 填充或截断序列到指定长度
padded_sequence = torch.tensor(
sequence_indices + [0] * (self.SEQUENCE_LENGTH - len(sequence_indices))
)[:self.SEQUENCE_LENGTH]
preprocessed_sequences.append(padded_sequence)
return preprocessed_sequences
def __len__(self):
"""
返回数据集中的样本数量
"""
return len(self.dataframe)
def __getitem__(self, idx):
"""
获取指定索引的数据样本
参数:
idx (int): 样本索引
返回:
tuple: (预处理后的文本序列, 处理后的图像张量, 对应的标签)
"""
# 获取图像路径和标签
image_path = self.dataframe.loc[idx, self.IMAGE_COL]
label = self.dataframe.loc[idx, self.LABEL_COL]
# 加载并处理图像
image = Image.open(os.path.join(image_path_prefix, image_path)).convert('RGB')
image = self.transform(image)
# 获取预处理后的文本序列
preprocessed_sequence = self.preprocessed_sequences[idx]
return preprocessed_sequence, image, label
"""
"""
文件功能说明:
这个文件实现了一个用于文本情感分析的数据集加载器。主要功能包括:
1. 从CSV文件中读取文本数据和对应的标签
2. 使用NLTK进行文本分词
3. 利用预训练的Word2Vec模型将文本转换为词向量序列
4. 对序列进行填充或截断,确保统一长度
5. 为深度学习模型提供标准化的数据接口
关键特性:
- 支持自定义序列长度
- 使用Word2Vec进行词向量表示
- 自动处理未知词和序列长度标准化
- 支持批量数据加载
"""
# 导入必要的库
from torch.utils.data import Dataset # PyTorch数据集基类
from nltk.tokenize import word_tokenize # NLTK分词工具
from gensim.models import Word2Vec # 词向量模型
import torch # PyTorch深度学习框架
import os # 文件路径处理
import pandas as pd # 数据处理库
dir = os.path.dirname(__file__)
csv_file_path = os.path.join(dir, '..', '..', 'data', 'processed', 'text.csv')
image_path_prefix = os.path.join(dir, '..', '..', 'data', 'processed', 'text')
word2vec_path = os.path.join(dir, '..', '..', 'data', 'models', 'WORD2VEC.model')
class TextDataset(Dataset):
"""
文本数据集类,继承自PyTorch的Dataset类
用于加载和预处理文本数据,将文本转换为模型可用的向量形式
"""
def __init__(self, text_column, label_column):
"""
初始化数据集
参数:
text_column (str): CSV文件中存储文本内容的列名
label_column (str): CSV文件中存储标签的列名
"""
# 读取CSV文件数据
self.dataframe = pd.read_csv(csv_file_path)
# 加载预训练的Word2Vec模型
self.word2vec_model = Word2Vec.load(word2vec_path)
# 提取标签数据
self.labels = self.dataframe[label_column].tolist()
# 设置序列最大长度
self.SEQUENCE_LENGTH = 100
# 存储文本列名
self.TEXT_COL = text_column
# 预处理所有文本数据
self.data = self._preprocess_text()
def _preprocess_text(self):
"""
预处理文本数据
功能:
1. 对文本进行分词
2. 将词转换为词向量索引
3. 对序列进行填充或截断
返回:
list: 处理后的文本序列列表
"""
preprocessed_sequences = []
for idx in range(len(self.dataframe)):
# 获取文本内容
text = self.dataframe.loc[idx, self.TEXT_COL]
# 使用NLTK进行分词
tokens = word_tokenize(text)
# 将词转换为词向量索引,忽略未知词
sequence_indices = [self.word2vec_model.wv.key_to_index[word]
for word in tokens
if word in self.word2vec_model.wv]
# 填充序列到指定长度(或截断)
padded_sequence = torch.tensor(
sequence_indices + [0] * (self.SEQUENCE_LENGTH - len(sequence_indices))
)[:self.SEQUENCE_LENGTH]
preprocessed_sequences.append(padded_sequence)
return preprocessed_sequences
def __len__(self):
"""
返回数据集中的样本数量
"""
return len(self.data)
def __getitem__(self, index):
"""
获取指定索引的数据样本
参数:
index (int): 样本索引
返回:
tuple: (处理后的文本序列张量, 对应的标签)
"""
data = self.data[index] # 获取预处理后的文本序列
label = self.labels[index] # 获取对应的标签
return data, label
\ No newline at end of file
from .image_model import ImageModel
from .image_model import ImageModel
from .text_model import TextModel
from .multi_modal_model import MultimodalModel
"""
"""
文件功能说明:
本文件实现了一个用于图像情感分析的CNN模型。主要功能包括:
1. 使用卷积神经网络处理图像数据
2. 提取图像的层次化特征
3. 支持单独的情感分类和多模态融合两种模式
4. 通过多层卷积和池化提取图像特征
关键特性:
- 4层卷积层结构,逐层提取更高层次特征
- 使用ReLU激活函数增加非线性
- 支持可配置的输出类别数
- 可选的多模态模式,用于特征提取
- 自适应的特征维度处理
"""
import torch.nn as nn
import numpy as np
import matplotlib.pyplot as plt
import torch
import torch.nn as nn
import os
class ImageModel(nn.Module):
"""
图像处理模型类,继承自PyTorch的nn.Module
用于处理图像数据并进行情感分类或特征提取
"""
def __init__(self, NUM_CLASSES, IMG_SHAPE, is_for_multimodal=False):
"""
初始化模型
参数:
NUM_CLASSES (int): 输出类别数量
IMG_SHAPE (int): 输入图像的尺寸
is_for_multimodal (bool): 是否用于多模态模型,默认False
"""
super(ImageModel, self).__init__()
# 保存模型参数
self.NUM_CLASSES = NUM_CLASSES
self.IMG_SHAPE = IMG_SHAPE
self.is_for_multimodal = is_for_multimodal
# 第一个卷积块:输入通道3(RGB),输出通道16
self.conv1 = nn.Conv2d(3, 16, kernel_size=3, stride=1, padding=1)
self.relu1 = nn.ReLU()
self.pool1 = nn.MaxPool2d(kernel_size=2, stride=2)
# 第二个卷积块:输入通道16,输出通道32
self.conv2 = nn.Conv2d(16, 32, kernel_size=3, stride=1, padding=1)
self.relu2 = nn.ReLU()
self.pool2 = nn.MaxPool2d(kernel_size=2, stride=2)
# 第三个卷积块:输入通道32,输出通道64
self.conv3 = nn.Conv2d(32, 64, kernel_size=3, stride=1, padding=1)
self.relu3 = nn.ReLU()
self.pool3 = nn.MaxPool2d(kernel_size=2, stride=2)
# 第四个卷积块:输入通道64,输出通道128
self.conv4 = nn.Conv2d(64, 128, kernel_size=3, stride=1, padding=1)
self.relu4 = nn.ReLU()
self.pool4 = nn.MaxPool2d(kernel_size=2, stride=2)
# 展平层,将特征图转换为一维向量
self.flatten = nn.Flatten()
# 全连接层,将特征映射到512维空间
self.fc1 = nn.Linear(128 * 14 * 14, 512)
self.relu5 = nn.ReLU()
# 如果不是多模态模式,添加分类层
if not self.is_for_multimodal:
self.fc2 = nn.Linear(512, 3)
self.softmax = nn.Softmax(dim=1)
def forward(self, x):
"""
前向传播函数
参数:
x (Tensor): 输入图像张量
返回:
Tensor: 分类结果或特征表示
"""
# 依次通过各个卷积块
x = self.conv1(x)
x = self.relu1(x)
x = self.pool1(x)
x = self.conv2(x)
x = self.relu2(x)
x = self.pool2(x)
x = self.conv3(x)
x = self.relu3(x)
x = self.pool3(x)
x = self.conv4(x)
x = self.relu4(x)
x = self.pool4(x)
# 展平特征图并通过全连接层
x = self.flatten(x)
x = self.fc1(x)
x = self.relu5(x)
# 如果不是多模态模式,进行分类
if not self.is_for_multimodal:
x = self.fc2(x)
x = self.softmax(x)
return x
# # Move tensor to CPU and convert to a numpy array
# feature_maps = x.detach().cpu().numpy()
# feature_maps = np.transpose(feature_maps, (0, 2, 3, 1)) # Rearrange dimensions for visualization
# # Display each channel in the feature maps
# for channel in range(feature_maps.shape[-1]):
# plt.imshow(feature_maps[0, :, :, channel], cmap='gray') # Assuming batch size = 1
# plt.show()
def visualize_model(self, save_path):
try:
from torchviz import make_dot
# 确保输出目录存在
os.makedirs(os.path.dirname(save_path), exist_ok=True)
# 创建一个示例输入
x = torch.randn(1, 3, 224, 224) # 假设输入大小为 224x224
y = self.forward(x)
# 生成计算图
dot = make_dot(y, params=dict(self.named_parameters()))
# 设置图形属性
dot.attr(rankdir='TB')
# 尝试渲染
print(f"正在尝试将图形保存到: {save_path}")
dot.render(save_path, format='png', cleanup=True)
return True
except Exception as e:
print(f"可视化过程中出错: {e}")
print("请确保:")
print("1. graphviz 和 torchviz 已正确安装")
print("2. 系统 PATH 中包含 Graphviz bin 目录")
return False
\ No newline at end of file
"""
"""
文件功能说明:
本文件实现了一个多模态情感分析模型,集成了文本和图像两种模态。主要功能包括:
1. 融合文本模型和图像模型的特征
2. 使用多头注意力机制处理不同模态的特征交互
3. 通过非线性层增强特征表达能力
4. 最终进行情感分类(积极、消极、中性)
关键特性:
- 多头注意力机制增强模态间交互
- 可配置的特征融合维度
- 灵活的注意力头数设置
- 分层次的特征处理架构
- 支持端到端训练
"""
import torch
import torch.nn as nn
import torch.nn.functional as F
class MultimodalModel(nn.Module):
"""
多模态模型类,继承自PyTorch的nn.Module
整合文本和图像特征进行情感分析
"""
def __init__(self, text_model, image_model, num_classes):
"""
初始化多模态模型
参数:
text_model (nn.Module): 预训练的文本处理模型
image_model (nn.Module): 预训练的图像处理模型
num_classes (int): 输出类别数量(通常为3:积极、消极、中性)
"""
super(MultimodalModel, self).__init__()
# 设置特征维度和注意力参数
fused_representation_size = 512 # 融合后的特征维度
image_fused_representation_size = 512 # 图像特征维度
text_fused_representation_size = 100 # 文本特征维度
num_attention_heads = 4 # 注意力头数量
# 保存子模型和参数
self.image_model = image_model # 图像处理模型
self.text_model = text_model # 文本处理模型
self.num_classes = num_classes # 分类类别数
# 多头注意力层
# 处理图像特征的注意力机制
self.image_attention = nn.MultiheadAttention(
image_fused_representation_size,
num_attention_heads
)
# 图像特征的线性变换层
self.image_attention_Linear = nn.Linear(
image_fused_representation_size,
fused_representation_size
)
# 处理文本特征的注意力机制
self.text_attention = nn.MultiheadAttention(
text_fused_representation_size,
num_attention_heads
)
# 文本特征的线性变换层
self.text_attention_Linear = nn.Linear(
text_fused_representation_size,
fused_representation_size
)
# 特征融合层
# 将文本和图像特征连接并映射到统一空间
self.fusion_layer = nn.Linear(
image_model.fc1.out_features + text_model.lstm1.hidden_size * 2,
fused_representation_size
)
# 非线性处理层
self.nonlinear_layer = nn.Linear(
fused_representation_size,
fused_representation_size
)
# 最终分类层
self.classification_layer = nn.Linear(
fused_representation_size,
num_classes
)
def forward(self, text, image):
"""
前向传播函数
参数:
text (Tensor): 文本输入张量
image (Tensor): 图像输入张量
返回:
Tensor: 情感分类的概率分布
"""
# 获取文本和图像特征
text_features = self.text_model(text) # 提取文本特征
image_features = self.image_model(image) # 提取图像特征
# 应用注意力机制
# 处理图像特征
image_attention_out, _ = self.image_attention(
image_features.unsqueeze(0),
image_features.unsqueeze(0),
image_features.unsqueeze(0)
)
image_attention_out = self.image_attention_Linear(
image_attention_out.squeeze(0)
)
# 处理文本特征
text_attention_out, _ = self.text_attention(
text_features.unsqueeze(0),
text_features.unsqueeze(0),
text_features.unsqueeze(0)
)
text_attention_out = self.text_attention_Linear(
text_attention_out.squeeze(0)
)
# 特征融合
# 连接文本和图像特征
combined_features = torch.cat(
[text_features, image_features],
dim=1
)
# 通过融合层
fused_features = self.fusion_layer(combined_features)
# 非线性处理
enhanced_features = F.relu(self.nonlinear_layer(fused_features))
# 最终分类
logits = self.classification_layer(enhanced_features)
return F.softmax(logits, dim=1)
def visualize_model(self, save_path='multimodal_model_architecture'):
"""
可视化模型结构
参数:
save_path (str): 保存图像的路径(不需要包含文件扩展名)
"""
try:
from torchviz import make_dot
import torch
# 创建示例输入
text = torch.randint(0, 1000, (1, 50)) # 文本输入
image = torch.randn(1, 3, 224, 224) # 图像输入
# 获取模型输出
y = self(text, image)
# 创建计算图
dot = make_dot(y, params=dict(self.named_parameters()))
# 设置图像格式
dot.attr(rankdir='TB')
dot.attr('node', shape='box')
# 确保文件名不包含扩展名
save_path = save_path.replace('.png', '').replace('.pdf', '')
# 保存图像
dot.render(save_path, format='png', cleanup=True)
print(f"多模态模型结构图已保存至: {save_path}.png")
except Exception as e:
print(f"生成模型结构图时出错: {str(e)}")
"""
"""
文件功能说明:
本文件实现了一个用于文本情感分析的神经网络模型。主要功能包括:
1. 使用预训练的Word2Vec模型进行词嵌入
2. 通过双向LSTM提取文本序列特征
3. 支持单独的情感分类和多模态融合两种模式
4. 使用Dropout防止过拟合
关键特性:
- 使用预训练词向量进行词嵌入
- 双向LSTM捕获上下文信息
- 可配置的隐藏层大小
- 支持多模态特征提取模式
- 灵活的分类层设计
"""
import torch
from torch import nn
import os
import pandas as pd
from gensim.models import Word2Vec
from pathlib import Path
class TextModel(nn.Module):
"""
文本处理模型类,继承自PyTorch的nn.Module
用于处理文本数据并进行情感分类或特征提取
"""
def __init__(self, NUM_CLASSES, is_for_multimodal=False):
"""
初始化模型
参数:
NUM_CLASSES (int): 输出类别数量
is_for_multimodal (bool): 是否用于多模态模型,默认False
"""
super(TextModel, self).__init__()
# 获取项目根目录
project_root = Path(__file__).parent.parent.parent
# 构建模型文件路径
model_path = project_root / "data" / "models" / "WORD2VEC.model"
if not model_path.exists():
print(f"警告: Word2Vec模型文件不存在: {model_path}")
print("请确保已训练并保存Word2Vec模型")
# 创建必要的目录
model_path.parent.mkdir(parents=True, exist_ok=True)
try:
self.word2vec_model = Word2Vec.load(str(model_path))
except Exception as e:
print(f"加载Word2Vec模型时出错: {e}")
print(f"请确保模型文件存在于: {model_path}")
raise
# 获取词嵌入矩阵
EMBEDDING_MATRIX = self.word2vec_model.wv.vectors
# 保存模型参数
self.is_for_multimodal = is_for_multimodal # 是否用于多模态模型
self.HIDDEN_SIZE = 50 # LSTM隐藏层大小
# 获取词汇表大小和词向量维度
vocab_size, embedding_dim = EMBEDDING_MATRIX.shape
# 词嵌入层:使用预训练的词向量,并冻结权重
self.embedding = nn.Embedding.from_pretrained(
torch.tensor(EMBEDDING_MATRIX),
freeze=True
)
# Dropout层:防止过拟合
self.dropout = nn.Dropout(0.5)
# 双向LSTM层:处理序列数据
self.lstm1 = nn.LSTM(
embedding_dim, # 输入维度:词向量维度
self.HIDDEN_SIZE, # 隐藏层大小
batch_first=True, # 批次维度在前
bidirectional=True # 使用双向LSTM
)
# 如果不是多模态模式,添加分类层
if not self.is_for_multimodal:
# 全连接层:将LSTM输出映射到类别空间
self.fc = nn.Linear(self.HIDDEN_SIZE * 2, NUM_CLASSES)
# Softmax层:计算类别概率
self.softmax = nn.Softmax(dim=1)
def forward(self, x):
"""
前向传播函数
参数:
x (Tensor): 输入文本的词索引序列
返回:
Tensor: 如果是多模态模式,返回特征表示;否则返回分类概率
"""
# 词嵌入层
embedded = self.embedding(x)
# 应用dropout
embedded = self.dropout(embedded)
# 通过LSTM层
output1, _ = self.lstm1(embedded)
# 获取最终的特征表示
# 连接最后一个时间步的前向和后向隐藏状态
last_hidden_state = torch.cat(
(output1[:, -1, :self.HIDDEN_SIZE], # 前向LSTM的最后隐藏状态
output1[:, 0, self.HIDDEN_SIZE:]), # 后向LSTM的第一个隐藏状态
dim=1
)
# 如果是多模态模式,直接返回特征
if self.is_for_multimodal:
return last_hidden_state
# 否则进行分类
logits = self.fc(last_hidden_state)
logits = self.softmax(logits)
return logits
def visualize_model(self, save_path='text_model_architecture'):
"""
可视化模型结构
参数:
save_path (str): 保存图像的路径(不需要包含文件扩展名)
"""
try:
from torchviz import make_dot
import torch
# 创建一个示例输入 (batch_size, sequence_length)
x = torch.randint(0, 1000, (1, 50)) # 假设词汇表大小为1000,序列长度为50
# 获取模型输出
y = self(x)
# 创建计算图
dot = make_dot(y, params=dict(self.named_parameters()))
# 设置图像格式
dot.attr(rankdir='TB')
dot.attr('node', shape='box')
# 确保文件名不包含扩展名
save_path = save_path.replace('.png', '').replace('.pdf', '')
# 保存图像
dot.render(save_path, format='png', cleanup=True)
print(f"文本模型结构图已保存至: {save_path}.png")
except Exception as e:
print(f"生成模型结构图时出错: {str(e)}")
\ No newline at end of file
{
{
"cells": [
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [
{
"ename": "ModuleNotFoundError",
"evalue": "No module named 'models'",
"output_type": "error",
"traceback": [
"\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[1;31mModuleNotFoundError\u001b[0m Traceback (most recent call last)",
"Cell \u001b[1;32mIn[2], line 2\u001b[0m\n\u001b[0;32m 1\u001b[0m \u001b[39mfrom\u001b[39;00m \u001b[39msklearn\u001b[39;00m\u001b[39m.\u001b[39;00m\u001b[39mmodel_selection\u001b[39;00m \u001b[39mimport\u001b[39;00m train_test_split\n\u001b[1;32m----> 2\u001b[0m \u001b[39mfrom\u001b[39;00m \u001b[39mmodels\u001b[39;00m \u001b[39mimport\u001b[39;00m ImageModel\n\u001b[0;32m 3\u001b[0m \u001b[39mfrom\u001b[39;00m \u001b[39mdataset_generators\u001b[39;00m \u001b[39mimport\u001b[39;00m ImageDataset\n\u001b[0;32m 4\u001b[0m \u001b[39mimport\u001b[39;00m \u001b[39mutils\u001b[39;00m \u001b[39mas\u001b[39;00m \u001b[39mut\u001b[39;00m\n",
"\u001b[1;31mModuleNotFoundError\u001b[0m: No module named 'models'"
]
}
],
"source": [
"from sklearn.model_selection import train_test_split\n",
"from models import ImageModel\n",
"from dataset_generators import ImageDataset\n",
"import utils as ut\n",
"import os\n",
"import numpy as np\n",
"from torch.utils.data import Subset, DataLoader\n",
"from torchviz import make_dot\n",
"import torch\n",
"import torch.nn as nn\n",
"import pandas as pd\n",
"from torch.utils.data import Dataset\n",
"import torchvision.transforms as transforms\n",
"from PIL import Image\n",
"import os"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def label_to_emotion(label):\n",
" return {\n",
" 0 : 'Surprise',\n",
" 1 : 'Fear',\n",
" 2 : 'Disgust',\n",
" 3 : 'Happiness',\n",
" 4 : 'Sadness',\n",
" 5 : 'Anger',\n",
" 6 : 'Neutral'\n",
" }[label]\n",
"\n",
"def get_emotion_by_id(emotion_id):\n",
" id_to_emotion = {\n",
" 1 : 'Surprise',\n",
" 2 : 'Fear',\n",
" 3 : 'Disgust',\n",
" 4 : 'Happiness',\n",
" 5 : 'Sadness',\n",
" 6 : 'Anger',\n",
" 7 : 'Neutral'\n",
" }\n",
" return id_to_emotion[emotion_id]"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "tf",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.16"
},
"orig_nbformat": 4
},
"nbformat": 4,
"nbformat_minor": 2
}
"""
"""
文件功能说明:
本文件是图像情感分析模型的训练脚本。主要功能包括:
1. 配置和初始化图像模型训练环境
2. 加载和预处理图像数据集
3. 实现完整的训练流程
4. 保存训练好的模型
关键特性:
- 支持GPU加速训练
- 使用SGD优化器
- 实现交叉熵损失
- 支持数据集划分
- 批量处理训练数据
"""
# 确保能够正确导入其他模块
if __name__ == '__main__' and __package__ is None:
import sys
from os import path
sys.path.append(path.dirname(path.dirname(path.abspath(__file__))))
# 导入必要的库和模块
from sklearn.model_selection import train_test_split # 数据集划分工具
from models import ImageModel # 图像模型类
from dataset_generators import ImageDataset # 图像数据集加载器
import utils as ut # 工具函数
import os
import numpy as np
from torch.utils.data import Subset, DataLoader # 数据加载工具
from torchviz import make_dot # 模型可视化工具
import torch
import torch.nn as nn
# 设置训练参数
MODEL_NAME = "IMAGES_MODEL" # 模型名称
IMAGE_SHAPE = 224 # 图像输入尺寸
IMAGE_COL = "local_path" # 图像路径列名
LABEL_COL = "label" # 标签列名
LR = 0.001 # 学习率
DEVICE = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu') # 设备选择
BATCH_SIZE = 228 # 批次大小
EPOCHS = 20 # 训练轮数
NUM_CLASSES = 3 # 分类类别数(积极、消极、中性)
# 加载数据集
data = ImageDataset(IMAGE_SHAPE, IMAGE_COL, LABEL_COL)
indices = np.arange(len(data))
# 划分训练集和测试集
train_indices, test_indices = train_test_split(
indices,
test_size=0.2, # 测试集占20%
random_state=42 # 固定随机种子
)
# 创建训练集和测试集的子集
train_data = Subset(data, train_indices)
test_data = Subset(data, test_indices)
# 创建数据加载器
train_loader = DataLoader(
train_data,
batch_size=BATCH_SIZE,
shuffle=True, # 随机打乱训练数据
pin_memory=True # 使用固定内存,提高GPU训练效率
)
test_loader = DataLoader(
test_data,
batch_size=BATCH_SIZE,
shuffle=False, # 测试数据不需要打乱
pin_memory=True
)
# 初始化模型
model = ImageModel(NUM_CLASSES, IMAGE_SHAPE).to(DEVICE)
# 定义损失函数和优化器
criterion = nn.CrossEntropyLoss() # 交叉熵损失
optimizer = torch.optim.SGD(model.parameters(), lr=LR) # SGD优化器
# 打印模型信息
print()
print(" ############# MODEL SUMMARY ############# ")
print()
print(model)
print()
print(" ############ ############# ############ ")
print()
# 开始训练
ut.train(
model=model,
train_loader=train_loader,
test_loader=test_loader,
EPOCHS=EPOCHS,
MODEL_NAME=MODEL_NAME,
optimizer=optimizer,
criterion=criterion,
DEVICE=DEVICE,
is_multimodal=False # 指定为单模态训练模式
)
# 以下是被注释掉的模型架构可视化代码
# text, _ = next(iter(train_loader))
# output = model(text.to(DEVICE))
# archi = make_dot(output, params=dict(model.named_parameters()))
# archi.save("images_model_archi", "C:/Users/MourtadaHouari/Desktop/sentiment-analysis/src/images")
# archi.render('C:/Users/MourtadaHouari/Desktop/sentiment-analysis/src/images/images_model_archi', format='png')
"""
"""
文件功能说明:
本文件是多模态情感分析模型的训练脚本。主要功能包括:
1. 加载和预处理多模态数据集
2. 初始化和配置多模态模型
3. 实现完整的训练流程
4. 保存训练好的模型
关键特性:
- 支持GPU加速训练
- 使用Adam优化器
- 实现交叉熵损失
- 支持数据集划分
- 提供训练进度监控
"""
# 确保能够正确导入其他模块
if __name__ == '__main__' and __package__ is None:
import sys
from os import path
sys.path.append( path.dirname( path.dirname( path.abspath(__file__) ) ) )
from sklearn.model_selection import train_test_split
from models import ImageModel, TextModel, MultimodalModel
from dataset_generators import MultimodalDataset
import utils as ut
import numpy as np
from torch.utils.data import Subset, DataLoader
import torch
import torch.nn as nn
MODEL_NAME = "MULTIMODAL_MODEL"
IMAGE_SHAPE = 224
TEXT_COL = "text_emo"
LABEL_COL = "label"
IMAGE_COL = "local_path"
NUM_CLASSES = 3
BATCH_SIZE = 258
LR = 0.001
DEVICE = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')
EPOCHS = 20
data = MultimodalDataset(IMAGE_SHAPE, TEXT_COL, IMAGE_COL, LABEL_COL)
indices = np.arange(len(data))
train_indices, test_indices = train_test_split(indices, test_size=0.2, random_state=42)
train_data = Subset(data, train_indices)
test_data = Subset(data, test_indices)
# create data loaders for train and test sets
train_loader = DataLoader(train_data, batch_size=BATCH_SIZE, shuffle=True, pin_memory=True)
test_loader = DataLoader(test_data, batch_size=BATCH_SIZE, shuffle=False, pin_memory=True)
text_model = TextModel(NUM_CLASSES, True).to(DEVICE)
image_model = ImageModel(NUM_CLASSES, IMAGE_SHAPE, True).to(DEVICE)
model = MultimodalModel(text_model, image_model, NUM_CLASSES).to(DEVICE)
criterion = nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(model.parameters(), lr=LR)
model
print()
print(" ############# MODEL SUMMARY ############# ")
print()
print(model)
print()
print(" ############ ############# ############ ")
print()
ut.train(model, train_loader, test_loader, EPOCHS, MODEL_NAME, optimizer, criterion, DEVICE, True)
"""
"""
文件功能说明:
这个文件是文本情感分析模型的训练脚本。主要功能包括:
1. 配置和初始化文本模型训练环境
2. 加载和预处理文本数据集
3. 实现完整的训练流程
4. 保存训练好的模型
关键特性:
- 支持GPU加速训练
- 使用Adam优化器
- 实现交叉熵损失
- 支持数据集划分
- 批量处理训练数据
"""
# 确保能够正确导入其他模块
if __name__ == '__main__' and __package__ is None:
import sys
from os import path
sys.path.append(path.dirname(path.dirname(path.abspath(__file__))))
# 导入必要的库和模块
from dataset_generators import TextDataset # 文本数据集加载器
from models import TextModel # 文本模型类
import torch
import torch.nn as nn
from torch.utils.data import Subset, DataLoader # 数据加载工具
import pandas as pd
from sklearn.model_selection import train_test_split # 数据集划分工具
import utils as ut # 工具函数
import numpy as np
from gensim.models import Word2Vec
import os
from pathlib import Path
from nltk.tokenize import TweetTokenizer
# 设置训练参数
MODEL_NAME = "RETRAINED_TEXT_MODEL" # 模型名称
TEXT_COL = "text_emo" # 文本列名
LABEL_COL = "label" # 标签列名
NUM_CLASSES = 3 # 分类类别数(积极、消极、中性)
BATCH_SIZE = 1024 # 批次大小
LR = 0.001 # 学习率
DEVICE = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu') # 设备选择
BATCH_SIZE = 2048 # 更新批次大小
EPOCHS = 20 # 训练轮数
# 加载数据集
data = TextDataset(TEXT_COL, LABEL_COL)
indices = np.arange(len(data))
# 划分训练集和测试集
train_indices, test_indices = train_test_split(
indices,
test_size=0.2, # 测试集占20%
random_state=42 # 固定随机种子
)
# 创建训练集和测试集的子集
train_data = Subset(data, train_indices)
test_data = Subset(data, test_indices)
# 创建数据加载器
train_loader = DataLoader(
train_data,
batch_size=BATCH_SIZE,
shuffle=True # 随机打乱训练数据
)
test_loader = DataLoader(
test_data,
batch_size=BATCH_SIZE,
shuffle=False # 测试数据不需要打乱
)
# 初始化模型
model = TextModel(NUM_CLASSES).to(DEVICE)
# 定义损失函数和优化器
criterion = nn.CrossEntropyLoss() # 交叉熵损失
optimizer = torch.optim.Adam(model.parameters(), lr=LR) # Adam优化器
# 打印模型信息
print()
print(" ############# MODEL SUMMARY ############# ")
print()
print(model)
print()
print(" ############ ############# ############ ")
print()
# 开始训练
ut.train(
model=model,
train_loader=train_loader,
test_loader=test_loader,
EPOCHS=EPOCHS,
MODEL_NAME=MODEL_NAME,
optimizer=optimizer,
criterion=criterion,
DEVICE=DEVICE,
is_multimodal=False # 指定为单模态训练模式
)
def train_word2vec():
"""训练并保存Word2Vec模型"""
# 加载数据
data = pd.read_csv('data/processed/processed_text_data.csv') # 请确保路径正确
# 文本预处理
tknzr = TweetTokenizer()
processed_texts = []
print("正在处理文本数据...")
for text in data['text_emo']: # 假设文本列名为 'text_emo'
# 清理和分词
cleaned_text = ut.clean_text(str(text))
tokens = tknzr.tokenize(cleaned_text)
tokens = ut.convert_emojis_to_word(tokens)
tokens = ut.remove_stopwords(tokens)
tokens = ut.remove_punctuation(tokens)
tokens = ut.stemm_words(tokens)
processed_texts.append(tokens)
print("正在训练Word2Vec模型...")
# 训练Word2Vec模型
model = Word2Vec(
sentences=processed_texts,
vector_size=100, # 词向量维度
window=5, # 上下文窗口大小
min_count=1, # 最小词频
workers=4 # 训练的线程数
)
# 保存模型
project_root = Path(__file__).parent.parent.parent
model_path = project_root / "data" / "models" / "WORD2VEC.model"
# 确保目录存在
model_path.parent.mkdir(parents=True, exist_ok=True)
print(f"正在保存模型到: {model_path}")
model.save(str(model_path))
print("Word2Vec模型训练完成并保存")
return model
def main():
"""主训练流程"""
# 首先确保Word2Vec模型存在
project_root = Path(__file__).parent.parent.parent
model_path = project_root / "data" / "models" / "WORD2VEC.model"
if not model_path.exists():
print("未找到预训练的Word2Vec模型,开始训练新模型...")
train_word2vec()
# 原有的模型训练代码...
# ...
if __name__ == "__main__":
main()
from .utils import *
from .utils import *
\ No newline at end of file
import sys
import sys
import os
from pathlib import Path
import torch
from graphviz import ExecutableNotFound
# 添加项目根目录到系统路径
sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(__file__))))
from src.models.image_model import ImageModel
def main():
try:
# 设置设备
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
# 创建模型实例
model = ImageModel(NUM_CLASSES=3, IMG_SHAPE=224, is_for_multimodal=False)
model = model.to(device)
# 设置保存路径
save_dir = 'outputs/model_visualization'
if not os.path.exists(save_dir):
os.makedirs(save_dir)
print(f"创建目录: {save_dir}")
save_path = os.path.join(save_dir, 'image_model_structure')
print(f"将保存模型结构图到: {save_path}")
# 在生成图之前添加路径检查
graphviz_path = os.environ.get('PATH', '').split(os.pathsep)
print("当前系统 PATH:", graphviz_path)
# 尝试直接指定 dot 可执行文件的路径
os.environ["PATH"] += os.pathsep + r"C:\Program Files\Graphviz\bin"
# 生成模型结构图
model.visualize_model(save_path)
# 验证文件是否生成
if os.path.exists(f"{save_path}.png"):
print(f"模型结构图已成功保存到: {save_path}.png")
else:
print("警告:PNG文件未能生成")
except ExecutableNotFound as e:
print(f"Graphviz错误: {e}")
print("请检查:")
print("1. Graphviz 是否正确安装 (dot -v)")
print("2. 环境变量是否正确设置")
print(f"当前 PATH: {os.environ['PATH']}")
except Exception as e:
print(f"发生其他错误: {e}")
if __name__ == '__main__':
main()
\ No newline at end of file
import sys
import sys
import os
import torch
# 添加项目根目录到系统路径
sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(__file__))))
from src.models.image_model import ImageModel
from src.models.text_model import TextModel
from src.models.multi_modal_model import MultimodalModel
def visualize_all_models(save_dir='outputs/model_visualization'):
"""
可视化所有模型的结构
参数:
save_dir (str): 保存模型结构图的目录
"""
try:
# 创建保存目录
if not os.path.exists(save_dir):
os.makedirs(save_dir)
print(f"创建目录: {save_dir}")
# 设置设备
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
# 1. 可视化图像模型
print("\n正在生成图像模型结构图...")
image_model = ImageModel(NUM_CLASSES=3, IMG_SHAPE=224, is_for_multimodal=True)
image_model = image_model.to(device)
save_path = os.path.join(save_dir, 'image_model_structure')
image_model.visualize_model(save_path)
# 2. 可视化文本模型
print("\n正在生成文本模型结构图...")
text_model = TextModel(NUM_CLASSES=3, is_for_multimodal=True)
text_model = text_model.to(device)
save_path = os.path.join(save_dir, 'text_model_structure')
text_model.visualize_model(save_path)
# 3. 可视化多模态模型
print("\n正在生成多模态模型结构图...")
multimodal_model = MultimodalModel(text_model, image_model, num_classes=3)
multimodal_model = multimodal_model.to(device)
save_path = os.path.join(save_dir, 'multimodal_model_structure')
multimodal_model.visualize_model(save_path)
print("\n所有模型结构图生成完成!")
except Exception as e:
print(f"发生错误: {str(e)}")
if __name__ == '__main__':
visualize_all_models()
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment