计算机竞赛 基于CNN实现谣言检测 - python 深度学习 机器学习

文章目录

  • 1 前言
    • 1.1 背景
  • 2 数据集
  • 3 实现过程
  • 4 CNN网络实现
  • 5 模型训练部分
  • 6 模型评估
  • 7 预测结果
  • 8 最后

1 前言

🔥 优质竞赛项目系列,今天要分享的是

基于CNN实现谣言检测

该项目较为新颖,适合作为竞赛课题方向,学长非常推荐!

🧿 更多资料, 项目分享:

https://gitee.com/dancheng-senior/postgraduate

1.1 背景

社交媒体的发展在加速信息传播的同时,也带来了虚假谣言信息的泛滥,往往会引发诸多不安定因素,并对经济和社会产生巨大的影响。

2 数据集

本项目所使用的数据是从新浪微博不实信息举报平台抓取的中文谣言数据,数据集中共包含1538条谣言和1849条非谣言。

如下图所示,每条数据均为json格式,其中text字段代表微博原文的文字内容。

在这里插入图片描述

每个文件夹里又有很多新闻文本。

在这里插入图片描述
每个文本又是json格式,具体内容如下:

在这里插入图片描述

3 实现过程

步骤入下:

*(1)解压数据,读取并解析数据,生成all_data.txt
*(2)生成数据字典,即dict.txt
*(3)生成数据列表,并进行训练集与验证集的划分,train_list.txt 、eval_list.txt
*(4)定义训练数据集提供器train_reader和验证数据集提供器eval_reader

import zipfile
import os
import io
import random
import json
import matplotlib.pyplot as plt
import numpy as np
import paddle
import paddle.fluid as fluid
from paddle.fluid.dygraph.nn import Conv2D, Linear, Embedding
from paddle.fluid.dygraph.base import to_variable

#解压原始数据集,将Rumor_Dataset.zip解压至data目录下
src_path="/home/aistudio/data/data36807/Rumor_Dataset.zip" #这里填写自己项目所在的数据集路径
target_path="/home/aistudio/data/Chinese_Rumor_Dataset-master"
if(not os.path.isdir(target_path)):
    z = zipfile.ZipFile(src_path, 'r')
    z.extractall(path=target_path)
    z.close()

#分别为谣言数据、非谣言数据、全部数据的文件路径
rumor_class_dirs = os.listdir(target_path+"非开源数据集") # 这里填写自己项目所在的数据集路径
non_rumor_class_dirs = os.listdir(target_path+"非开源数据集")
original_microblog = target_path+"非开源数据集"
#谣言标签为0,非谣言标签为1
rumor_label="0"
non_rumor_label="1"

#分别统计谣言数据与非谣言数据的总数
rumor_num = 0
non_rumor_num = 0
all_rumor_list = []
all_non_rumor_list = []

#解析谣言数据
for rumor_class_dir in rumor_class_dirs: 
    if(rumor_class_dir != '.DS_Store'):
        #遍历谣言数据,并解析
        with open(original_microblog + rumor_class_dir, 'r') as f:
            rumor_content = f.read()
        rumor_dict = json.loads(rumor_content)
        all_rumor_list.append(rumor_label+"\t"+rumor_dict["text"]+"\n")
        rumor_num +=1
#解析非谣言数据
for non_rumor_class_dir in non_rumor_class_dirs: 
    if(non_rumor_class_dir != '.DS_Store'):
        with open(original_microblog + non_rumor_class_dir, 'r') as f2:
            non_rumor_content = f2.read()
        non_rumor_dict = json.loads(non_rumor_content)
        all_non_rumor_list.append(non_rumor_label+"\t"+non_rumor_dict["text"]+"\n")
        non_rumor_num +=1
        
print("谣言数据总量为:"+str(rumor_num))
print("非谣言数据总量为:"+str(non_rumor_num))

#全部数据进行乱序后写入all_data.txt
data_list_path="/home/aistudio/data/"
all_data_path=data_list_path + "all_data.txt"
all_data_list = all_rumor_list + all_non_rumor_list

random.shuffle(all_data_list)

#在生成all_data.txt之前,首先将其清空
with open(all_data_path, 'w') as f:
    f.seek(0)
    f.truncate() 
    
with open(all_data_path, 'a') as f:
    for data in all_data_list:
        f.write(data) 
print('all_data.txt已生成')

在这里插入图片描述

接下来就是生成数据字典。


# 生成数据字典
def create_dict(data_path, dict_path):
with open(dict_path, ‘w’) as f:
f.seek(0)
f.truncate()

    dict_set = set()
    # 读取全部数据
    with open(data_path, 'r', encoding='utf-8') as f:
        lines = f.readlines()
    # 把数据生成一个元组
    for line in lines:
        content = line.split('\t')[-1].replace('\n', '')
        for s in content:
            dict_set.add(s)
    # 把元组转换成字典,一个字对应一个数字
    dict_list = []
    i = 0
    for s in dict_set:
        dict_list.append([s, i])
        i += 1
    # 添加未知字符
    dict_txt = dict(dict_list)
    end_dict = {"": i}
    dict_txt.update(end_dict)
    # 把这些字典保存到本地中
    with open(dict_path, 'w', encoding='utf-8') as f:
        f.write(str(dict_txt))
    print("数据字典生成完成!",'\t','字典长度为:',len(dict_list))

我们可以查看一下dict_txt的内容

在这里插入图片描述

接下来就是数据列表的生成


# 创建序列化表示的数据,并按照一定比例划分训练数据与验证数据
def create_data_list(data_list_path):

    with open(os.path.join(data_list_path, 'dict.txt'), 'r', encoding='utf-8') as f_data:
        dict_txt = eval(f_data.readlines()[0])

    with open(os.path.join(data_list_path, 'all_data.txt'), 'r', encoding='utf-8') as f_data:
        lines = f_data.readlines()
    
    i = 0
    with open(os.path.join(data_list_path, 'eval_list.txt'), 'a', encoding='utf-8') as f_eval,\
    open(os.path.join(data_list_path, 'train_list.txt'), 'a', encoding='utf-8') as f_train:
        for line in lines:
            title = line.split('\t')[-1].replace('\n', '')
            lab = line.split('\t')[0]
            t_ids = ""
            if i % 8 == 0:
                for s in title:
                    temp = str(dict_txt[s])
                    t_ids = t_ids + temp + ','
                t_ids = t_ids[:-1] + '\t' + lab + '\n'
                f_eval.write(t_ids)
            else:
                for s in title:
                    temp = str(dict_txt[s])
                    t_ids = t_ids + temp + ','
                t_ids = t_ids[:-1] + '\t' + lab + '\n'
                f_train.write(t_ids)
            i += 1
        
    print("数据列表生成完成!")

定义数据读取器


def data_reader(file_path, phrase, shuffle=False):
all_data = []
with io.open(file_path, “r”, encoding=‘utf8’) as fin:
for line in fin:
cols = line.strip().split(“\t”)
if len(cols) != 2:
continue
label = int(cols[1])

            wids = cols[0].split(",")
            all_data.append((wids, label))

    if shuffle:
        if phrase == "train":
            random.shuffle(all_data)

    def reader():
        for doc, label in all_data:
            yield doc, label
    return reader

class SentaProcessor(object):
    def __init__(self, data_dir,):
        self.data_dir = data_dir
        
    def get_train_data(self, data_dir, shuffle):
        return data_reader((self.data_dir + "train_list.txt"), 
                            "train", shuffle)

    def get_eval_data(self, data_dir, shuffle):
        return data_reader((self.data_dir + "eval_list.txt"), 
                            "eval", shuffle)

    def data_generator(self, batch_size, phase='train', shuffle=True):
        if phase == "train":
            return paddle.batch(
                self.get_train_data(self.data_dir, shuffle),
                batch_size,
                drop_last=True)
        elif phase == "eval":
            return paddle.batch(
                self.get_eval_data(self.data_dir, shuffle),
                batch_size,
                drop_last=True)
        else:
            raise ValueError(
                "Unknown phase, which should be in ['train', 'eval']")

总之在数据处理这一块需要我们注意的是一共生成以下的几个文件。

在这里插入图片描述

4 CNN网络实现

接下来就是构建以及配置卷积神经网络(Convolutional Neural Networks,
CNN),开篇也说了,其实这里有很多模型的选择,之所以选择CNN是因为让我们熟悉CNN的相关实现。 输入词向量序列,产生一个特征图(feature
map),对特征图采用时间维度上的最大池化(max pooling over
time)操作得到此卷积核对应的整句话的特征,最后,将所有卷积核得到的特征拼接起来即为文本的定长向量表示,对于文本分类问题,将其连接至softmax即构建出完整的模型。在实际应用中,我们会使用多个卷积核来处理句子,窗口大小相同的卷积核堆叠起来形成一个矩阵,这样可以更高效的完成运算。另外,我们也可使用窗口大小不同的卷积核来处理句子。具体的流程如下:

在这里插入图片描述
首先我们构建单层CNN神经网络。



    #单层
    class SimpleConvPool(fluid.dygraph.Layer):
        def __init__(self,
                     num_channels, # 通道数
                     num_filters,  # 卷积核数量
                     filter_size,  # 卷积核大小
                     batch_size=None): # 16
            super(SimpleConvPool, self).__init__()
            self.batch_size = batch_size
            self._conv2d = Conv2D(num_channels = num_channels,
                num_filters = num_filters,
                filter_size = filter_size,
                act='tanh')
            self._pool2d = fluid.dygraph.Pool2D(
                pool_size = (150 - filter_size[0]+1,1),
                pool_type = 'max',
                pool_stride=1
            )
    
        def forward(self, inputs):
            # print('SimpleConvPool_inputs数据纬度',inputs.shape) # [16, 1, 148, 128]
            x = self._conv2d(inputs)
            x = self._pool2d(x)
            x = fluid.layers.reshape(x, shape=[self.batch_size, -1])
            return x



    class CNN(fluid.dygraph.Layer):
        def __init__(self):
            super(CNN, self).__init__()
            self.dict_dim = train_parameters["vocab_size"]
            self.emb_dim = 128   #emb纬度
            self.hid_dim = [32]  #卷积核数量
            self.fc_hid_dim = 96  #fc参数纬度
            self.class_dim = 2    #分类数
            self.channels = 1     #输入通道数
            self.win_size = [[3, 128]]  # 卷积核尺寸
            self.batch_size = train_parameters["batch_size"] 
            self.seq_len = train_parameters["padding_size"]
            self.embedding = Embedding( 
                size=[self.dict_dim + 1, self.emb_dim],
                dtype='float32', 
                is_sparse=False)
            self._simple_conv_pool_1 = SimpleConvPool(
                self.channels,
                self.hid_dim[0],
                self.win_size[0],
                batch_size=self.batch_size)
            self._fc1 = Linear(input_dim = self.hid_dim[0],
                                output_dim = self.fc_hid_dim,
                                act="tanh")
            self._fc_prediction = Linear(input_dim = self.fc_hid_dim,
                                        output_dim = self.class_dim,
                                        act="softmax")
    
        def forward(self, inputs, label=None):
    
            emb = self.embedding(inputs) # [2400, 128]
            # print('CNN_emb',emb.shape)  
            emb = fluid.layers.reshape(   # [16, 1, 150, 128]
                emb, shape=[-1, self.channels , self.seq_len, self.emb_dim])
            # print('CNN_emb',emb.shape)
            conv_3 = self._simple_conv_pool_1(emb)
            fc_1 = self._fc1(conv_3)
            prediction = self._fc_prediction(fc_1)
            if label is not None:
                acc = fluid.layers.accuracy(prediction, label=label)
                return prediction, acc
            else:
                return prediction



接下来就是参数的配置,不过为了在模型训练过程中更直观的查看我们训练的准确率,我们首先利用python的matplotlib.pyplt函数实现一个可视化图,具体的实现如下:


def draw_train_process(iters, train_loss, train_accs):
title=“training loss/training accs”
plt.title(title, fontsize=24)
plt.xlabel(“iter”, fontsize=14)
plt.ylabel(“loss/acc”, fontsize=14)
plt.plot(iters, train_loss, color=‘red’, label=‘training loss’)
plt.plot(iters, train_accs, color=‘green’, label=‘training accs’)
plt.legend()
plt.grid()
plt.show()

5 模型训练部分


def train():
with fluid.dygraph.guard(place = fluid.CUDAPlace(0)): # 因为要进行很大规模的训练,因此我们用的是GPU,如果没有安装GPU的可以使用下面一句,把这句代码注释掉即可
# with fluid.dygraph.guard(place = fluid.CPUPlace()):

        processor = SentaProcessor( data_dir="data/")
    
        train_data_generator = processor.data_generator(
            batch_size=train_parameters["batch_size"],
            phase='train',
            shuffle=True)
            
        model = CNN()
        sgd_optimizer = fluid.optimizer.Adagrad(learning_rate=train_parameters["adam"],parameter_list=model.parameters())
        steps = 0
        Iters,total_loss, total_acc = [], [], []
        for eop in range(train_parameters["epoch"]):
            for batch_id, data in enumerate(train_data_generator()):
                steps += 1
                #转换为 variable 类型
                doc = to_variable(
                    np.array([
                        np.pad(x[0][0:train_parameters["padding_size"]],  #对句子进行padding,全部填补为定长150
                              (0, train_parameters["padding_size"] - len(x[0][0:train_parameters["padding_size"]])),
                               'constant',
                              constant_values=(train_parameters["vocab_size"])) # 用  的id 进行填补
                        for x in data
                    ]).astype('int64').reshape(-1))
                #转换为 variable 类型
                label = to_variable(
                    np.array([x[1] for x in data]).astype('int64').reshape(
                        train_parameters["batch_size"], 1))

                model.train() #使用训练模式
                prediction, acc = model(doc, label)
                loss = fluid.layers.cross_entropy(prediction, label)
                avg_loss = fluid.layers.mean(loss)
                avg_loss.backward()
                sgd_optimizer.minimize(avg_loss)
                model.clear_gradients()
                
                if steps % train_parameters["skip_steps"] == 0:
                    Iters.append(steps)
                    total_loss.append(avg_loss.numpy()[0])
                    total_acc.append(acc.numpy()[0])
                    print("eop: %d, step: %d, ave loss: %f, ave acc: %f" %
                         (eop, steps,avg_loss.numpy(),acc.numpy()))
                if steps % train_parameters["save_steps"] == 0:
                    save_path = train_parameters["checkpoints"]+"/"+"save_dir_" + str(steps)
                    print('save model to: ' + save_path)
                    fluid.dygraph.save_dygraph(model.state_dict(),
                                                   save_path)
                # break
    draw_train_process(Iters, total_loss, total_acc)

训练的过程以及训练的结果如下:

在这里插入图片描述

6 模型评估


def to_eval():
with fluid.dygraph.guard(place = fluid.CUDAPlace(0)):
processor = SentaProcessor(data_dir=“data/”) #写自己的路径

        eval_data_generator = processor.data_generator(
                batch_size=train_parameters["batch_size"],
                phase='eval',
                shuffle=False)

        model_eval = CNN() #示例化模型
        model, _ = fluid.load_dygraph("data//save_dir_180.pdparams") #写自己的路径
        model_eval.load_dict(model)

        model_eval.eval() # 切换为eval模式
        total_eval_cost, total_eval_acc = [], []
        for eval_batch_id, eval_data in enumerate(eval_data_generator()):
            eval_np_doc = np.array([np.pad(x[0][0:train_parameters["padding_size"]],
                                    (0, train_parameters["padding_size"] -len(x[0][0:train_parameters["padding_size"]])),
                                    'constant',
                                    constant_values=(train_parameters["vocab_size"]))
                            for x in eval_data
                            ]).astype('int64').reshape(-1)
            eval_label = to_variable(
                                    np.array([x[1] for x in eval_data]).astype(
                                    'int64').reshape(train_parameters["batch_size"], 1))
            eval_doc = to_variable(eval_np_doc)
            eval_prediction, eval_acc = model_eval(eval_doc, eval_label)
            loss = fluid.layers.cross_entropy(eval_prediction, eval_label)
            avg_loss = fluid.layers.mean(loss)
            total_eval_cost.append(avg_loss.numpy()[0])
            total_eval_acc.append(eval_acc.numpy()[0])

    print("Final validation result: ave loss: %f, ave acc: %f" %
        (np.mean(total_eval_cost), np.mean(total_eval_acc) ))   

评估准确率如下:

在这里插入图片描述

7 预测结果


# 获取数据
def load_data(sentence):
# 读取数据字典
with open(‘data/dict.txt’, ‘r’, encoding=‘utf-8’) as f_data:
dict_txt = eval(f_data.readlines()[0])
dict_txt = dict(dict_txt)
# 把字符串数据转换成列表数据
keys = dict_txt.keys()
data = []
for s in sentence:
# 判断是否存在未知字符
if not s in keys:
s = ‘’
data.append(int(dict_txt[s]))
return data

train_parameters["batch_size"] = 1
lab = [ '谣言', '非谣言']
 
with fluid.dygraph.guard(place = fluid.CUDAPlace(0)):
    
    data = load_data('兴仁县今天抢小孩没抢走,把孩子母亲捅了一刀,看见这车的注意了,真事,车牌号辽HFM055!!!!!赶紧散播! 都别带孩子出去瞎转悠了 尤其别让老人自己带孩子出去 太危险了 注意了!!!!辽HFM055北京现代朗动,在各学校门口抢小孩!!!110已经 证实!!全市通缉!!')
    data_np = np.array(data)
    data_np = np.array(np.pad(data_np,(0,150-len(data_np)),"constant",constant_values =train_parameters["vocab_size"])).astype('int64').reshape(-1)

    infer_np_doc = to_variable(data_np)
   
    model_infer = CNN()
    model, _ = fluid.load_dygraph("data/save_dir_900.pdparams")
    model_infer.load_dict(model)
    model_infer.eval()
    result = model_infer(infer_np_doc)
    print('预测结果为:', lab[np.argmax(result.numpy())])

在这里插入图片描述

8 最后

🧿 更多资料, 项目分享:

https://gitee.com/dancheng-senior/postgraduate

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/83836.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

opencv光流估计

光流估计 光流是空间运动物体在观测成像平面上的像素运动的“瞬时速度”,根据各个像素点的速度矢量特征,可以对图像进行动态分析,例如目标跟踪。 返回: 亮度恒定:同一点随着时间的变化,其亮度不会发生改变…

【STM32】串口通信乱码(认识系统时钟来源)

使用 stm32f407 与电脑主机进行串口通信时,串口助手打印乱码,主要从以下方面进行排查: 检查传输协议设置是否一致(波特率、数据位、停止位、校验位)检查MCU外部晶振频率是否和库函数设置的一致 最终发现是外部晶振频…

MySQL的安装以及卸载

下载官网 https://www.mysql.com/ 切到下载tab页 找到 MySQL Community Server 或者 MySQL Community (GPL) Downloads --> MySQL Community Server 点击download按钮: 点击download进入下载页面选择No thanks, just start my download就可以开始下载了。 下…

使用 Terraform 与事件驱动的 Amazon CodeBuild 提升云上数据应用运维效率

背景信息 企业客户在云上部署的一系列数据应用的过程中,数据开发团队往往负责脚本内容,而其背后一系列云上资源的管理通常由一支云运维职能团队通过 IaC(Infrastructre as Code)实现。然而,当数据开发团队开发及部署相…

CentOS系统环境搭建(十四)——CentOS7.9安装elasticsearch-head

centos系统环境搭建专栏🔗点击跳转 关于node的安装请看上一篇CentOS系统环境搭建(十三)——CentOS7安装nvm,🔗点击跳转。 CentOS7.9安装elasticsearch-head 文章目录 CentOS7.9安装elasticsearch-head1.下载2.解压3.修…

matlab RANSAC拟合多项式曲线

目录 一、功能概述1、算法概述2、主要函数3、参考文献二、代码实现三、结果展示四、参考链接本文由CSDN点云侠原创,原文链接。爬虫网站自重,把自己当个人。爬些不完整的误导别人有意思吗???? 一、功能概述 1、算法概述 使用RANSAC对点进行多项式拟合。

【管理运筹学】第 5 章 | 整数规划 (2,割平面法及 0-1 变量的特性)

文章目录 引言三、割平面法四、0-1 型整数规划4.1 0-1 变量的特性4.1.1 投资问题4.1.2 约束条件满足个数问题 写在最后 引言 前文我们介绍了整数规划的一种求解方法——分支定界法,可以求解纯整数和混合整数规划问题。现在我们来学习另一种整数规划求解方法——割平…

好消息,微信又有免费提现活动了

​明天就是一年一度的七夕佳节,微信推出了「浪漫七夕,情寄明灯」活动,凡参与活动都可获得免费提现券等奖励。 01 活动时间 8 月 21 日 10 点至 8 月 24 日 24 点。 02 如何参与 活动入口: 在「微信支付有优惠」小程序专属入口…

Linux journalctl命令详解(journalctl指令)

文章目录 Linux Journalctl命令详解1. Journalctl简介2. Journalctl基础使用3. 过滤日志条目4. 时间戳和日志轮转5. 高级应用6. journalctl --help指令文档英文中文 注意事项journal日志不会将程序输出的空行显示,日志会被压缩得满满当当。journal日志不会自动持久化…

nginx代理webSocket链接响应403

一、场景 使用nginx代理webSocket链接,nginx响应403 1、nginx访问日志响应403 [18/Aug/2023:09:56:36 0800] "GET /FS_WEB_ASS/webim_api/socket/message HTTP/1.1" 403 5 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit…

【腾讯云 TDSQL-C Serverless 产品体验】基于腾讯云轻量服务器以及 TDSQL-C 搭建 LNMP WordPress 博客系统

文章目录 一、前言二、数据库发展与云原生数据库2.1 数据库发展简介2.2 云原生数据库简介2.2.1 云数据库与云原生数据库区别 三、腾讯云 TDSQL-C 数据库3.1 什么是腾讯云 TDSQL-C 数据库3.2 为什么推出 TDSQL-C 数据库?传统 MySQL 架构存在较多痛点3.2.1 传统 MySQL…

35_windows环境debug Nginx 源码-CLion配置CMake和启动

文章目录 生成 CMakeLists.txt 组态档35_windows环境debug Nginx 源码-CLion配置CMake和启动生成 CMakeLists.txt 组态档 修改auto目录configure文件,在 . auto/make 上边增加 . auto/cmake, 大概在 106 行。在 auto 目录下创建cmake 文件其内容如下: #!/usr/bin/env bash NG…

从入门到精通Python隧道代理的使用与优化

哈喽,Python爬虫小伙伴们!今天我们来聊聊如何从入门到精通地使用和优化Python隧道代理,让我们的爬虫程序更加稳定、高效!今天我们将对使用和优化进行一个简单的梳理,并且会提供相应的代码示例。 1. 什么是隧道代理&…

AI 绘画Stable Diffusion 研究(十三)SD数字人制作工具SadTlaker使用教程

免责声明: 本案例所用安装包免费提供,无任何盈利目的。 大家好,我是风雨无阻。 想必大家经常看到,无论是在产品营销还是品牌推广时,很多人经常以数字人的方式来为自己创造财富。而市面上的数字人收费都比较昂贵,少则几…

JS加密的域名锁定功能,JShaman支持泛域名

JShaman的域名锁定功能,支持泛域名 JShaman的JS代码混淆加密中,有一项“域名锁定”功能。使用此功能后,代码运行时会检测浏览器地址中的域名信息,如是非指定域名,则不运行,以此防止自己网站的JS代码被复制…

吐血整理,接口自动化测试-接口依赖/上传接口处理(项目实例)

目录:导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结(尾部小惊喜) 前言 常见的两种接口依…

嵌入式基础知识-中断处理过程

本篇来介绍中断,这是计算机系统以及嵌入式系统的重要概念。 1 中断基本概念 中断是CPU对系统发生的某个事件作出的一种反应。 中断的一些基本概念: 中断源:引起中断的事件称为中断源中断请求:中断源向CPU提出处理的请求称为中断…

最新AI系统ChatGPT网站程序源码/搭建教程/支持GPT4.0/Dall-E2绘画/支持MJ以图生图/H5端/自定义训练知识库

一、正文 SparkAi系统是基于国外很火的ChatGPT进行开发的Ai智能问答系统。本期针对源码系统整体测试下来非常完美,可以说SparkAi是目前国内一款的ChatGPT对接OpenAI软件系统。 那么如何搭建部署AI创作ChatGPT?小编这里写一个详细图文教程吧&#xff01…

C linux struct sigaction

在linux中定义struct sigaction结构体时, 在已经包含signal.h头文件的情况下, 仍旧提示找不到这个结构体. 需要在代码中定义 _POSIX_C_SOURCE 宏,并将其设为大于等于 199309L 的值。这样可以确保相关的函数和结构体在编译时可用。 这将告诉编译器以符合 POSIX 标准要…

Java 计算生肖,java Data中获取年,根据生日日期获取生肖注解,根据输入时间获取生肖,自定义注解的方式获取生肖 根据年份时间获取十二生肖

最近,开发中需要增加生肖,但是不想增加字段,于是通过注解的方式,实现生日与生肖的转换。 话不多说,直接上代码,如下: 实体类中的字段,添加自定义注解(ToChineseZodiacSe…