【Time Series】LSTM代码实战

一、简介

        还是那句话,"时间序列+金融"是一个很有"钱"景的话题,还是想尝试采用Stock+时间序列预测任务+DeepLearning。本文提供了LSTM预测股票的源代码。

二、算法原理

        长短期记忆网络(LSTM)是一种特殊的循环神经网络(RNN),用于处理和预测序列数据的时间依赖性。LSTM 能够学习长期依赖信息,解决了传统 RNN 在长序列训练过程中遇到的梯度消失或梯度爆炸问题。

        LSTM 通过引入三个门(遗忘门、输入门和输出门)和一个单元状态来解决长期依赖问题。这些门控制着信息的保留、遗忘与更新,使得 LSTM 能够有效地保留长期记忆并过滤掉不相关信息。单元状态在时间序列中穿行,允许信息的长期流动。门控制机制让 LSTM 有能力学习决定何时更新记忆、何时重置记忆以及何时让记忆通过无损坏地。

        1. 输入门(Input Gate)

        LSTM的每个单元接收三个输入:当前时刻的输入数据(x_t),上一个时刻的隐藏状态(h_{t-1}),以及上一个时刻的单元状态(C_{t-1})。输入门用来决定哪些新的信息将被添加到单元状态。

  • 忘记门层(Forget Gate Layer):首先,用一个sigmoid函数来决定从单元状态中丢弃什么信息。这个步骤通过 (f_t = \sigma(W_f \cdot [h_{t-1}, x_t] + b_f))计算得出,其中(W_f)是权重矩阵,(b_f)是偏置项。

  • 输入门层(Input Gate Layer):接着,使用另一个sigmoid层来决定将哪些新信息更新到单元状态中,(i_t = \sigma(W_i \cdot [h_{t-1}, x_t] + b_i))。同时,一个tanh层会创建一个新的候选值向量(\tilde{C}t = \tanh(W_C \cdot [h{t-1}, x_t] + b_C)),与(i_t)相乘,以决定更新什么值。

    2. 更新单元状态(Update Cell State)

    单元状态(C_{t-1})通过忘记旧信息(乘以(f_t))和增加新信息((i_t * \tilde{C}_t))来更新。

  • 首先,之前的单元状态通过与忘记门的输出相乘,丢弃我们决定忘记的信息。
  • 接着,将输入门的输出与新的候选值相乘,来增加新的信息。
  • 单元状态的更新公式为(C_t = f_t * C_{t-1} + i_t * \tilde{C}_t),这使得网络能够在每个时刻自行调节信息的存储。

    3. 输出门(Output Gate)和隐藏状态

        最后,决定输出的部分信息基于单元状态,但首先会过一个激活函数(通常是tanh)来确保数据值位于-1到1之间,然后乘以输出门(通过sigmoid层决定哪一部分的单元状态将输出)的输出。

  • 输出门层(Output Gate Layer)(o_t = \sigma(W_o \cdot [h_{t-1}, x_t] + b_o)),决定了单元状态中哪些信息将用于输出。

  • 计算当前时刻隐藏状态((h_t))(h_t = o_t * \tanh(C_t)),这里,我们将单元状态通过tanh激活函数处理(为了规范化),并且将其与输出门的输出相乘,来决定最终的输出是什么。

三、代码

        运行代码时的注意事项:按照配置项创建好对应的文件夹,准备好数据,数据来源我的上一篇blog《【Time Series】获取股票数据代码实战》可以找到。

import os
import random
from tqdm import tqdm
import joblib
import torch
import torch.nn as nn
from torch.utils.data import DataLoader, TensorDataset
import numpy as np
import pandas as pd
from sklearn.preprocessing import MinMaxScaler
from sklearn.metrics import mean_squared_error,mean_absolute_error

#配置项
class configs():
    def __init__(self):
        # Data
        self.data_input_path = r'../data/input'
        self.data_output_path = r'../data/output'
        self.save_model_dir = '../data/output'

        self.data_inputfile_name = r'五粮液.xlsx'
        self.data_BaseTrue_infer_output_name = r'基于真实数据推理结果.xlsx'
        self.data_BaseSelf_infer_output_name = r'基于自回归推理结果.xlsx'

        self.data_split_ratio = "0.8#0.1#0.1"


        self.model_name = 'LSTM'
        self.seed = 2024

        self.device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
        self.epoch = 50
        self.train_batch_size = 16
        self.in_seq_embeddings = 1 #输入的特征维度
        self.out_seq_embeddings = 1 #输出的特征维度
        self.in_seq_length = 5 #输入的时间窗口
        self.out_seq_length = 1 #输出的时间窗口

        self.hidden_features = 16  # 隐层数量

        self.learning_rate = 0.001
        self.dropout = 0.5

        self.istrain = True
        self.istest = True
        self.BaseTrue_infer = True
        self.BaseSelf_infer = True
        self.num_predictions = 800

cfg = configs()

def seed_everything(seed=2024):
    random.seed(seed)
    os.environ['PYTHONHASHSEED']=str(seed)
    np.random.seed(seed)
    torch.manual_seed(seed)

seed_everything(seed = cfg.seed)

#数据
class Define_Data():
    def __init__(self,task_type='train'):
        self.scaler = MinMaxScaler()
        self.df = pd.DataFrame()
        self.task_type = task_type

    #用于更新输入数据,设定选用从m行到n行的数据进行训/测,use_lines = "[m,n]"/"-1"
    def refresh_df_data(self,tmp_df_path,tmp_df_sheet_name,use_lines):
        self.df = pd.read_excel(tmp_df_path, sheet_name=tmp_df_sheet_name)
        if use_lines != "-1":
            use_lines = eval(use_lines)
            assert use_lines[0] <= use_lines[1]
            self.df = self.df.iloc[use_lines[0]:use_lines[1],:]

    #创建时间窗口数据,in_seq_length 为输入时间窗口,out_seq_length 为输出时间窗口
    def create_inout_sequences(self,input_data, in_seq_length, out_seq_length):
        inout_seq = []
        L = len(input_data)
        for i in range(L - in_seq_length):
            # 这里确保每个序列将是 tw x cfg.out_seq_length 的大小,这对应于 (seq_len, input_size)
            train_seq = input_data[i:i + in_seq_length][..., np.newaxis]  # np.newaxis 增加一个维度
            train_label = input_data[i + in_seq_length:i + in_seq_length + out_seq_length, np.newaxis]
            inout_seq.append((train_seq, train_label))
        return inout_seq

    #将时序数据转换为模型的输入形式
    def _collate_fn(self,batch):
        # Each element in 'batch' is a tuple (sequence, label)
        # We stack the sequences and labels separately to produce two tensors
        seqs, labels = zip(*batch)

        # Now we reshape these tensors to have size (seq_len, batch_size, input_size)
        seq_tensor = torch.stack(seqs).transpose(0, 1)

        # For labels, it might be just a single dimension outputs,
        # so we only need to stack and then add an extra dimension if necessary
        label_tensor = torch.stack(labels).transpose(0, 1)
        if len(label_tensor.shape) == 2:
            label_tensor = label_tensor.unsqueeze(-1)  # Add input_size dimension
        return seq_tensor, label_tensor

    #将表格数据构建成tensor格式
    def get_tensor_data(self):
        #缩放
        self.df['new_close'] = self.scaler.fit_transform(self.df[['close']])

        inout_seq = self.create_inout_sequences(self.df['new_close'].values,
                                                in_seq_length=cfg.in_seq_length,
                                                out_seq_length=cfg.out_seq_length)

        if self.task_type == 'train':
            # 准备训练数据
            X = torch.FloatTensor(np.array([s[0] for s in inout_seq]))
            y = torch.FloatTensor(np.array([s[1] for s in inout_seq]))

            # 划分训练集和测试集
            data_split_ratio = cfg.data_split_ratio
            data_split_ratio = [float(d) for d in data_split_ratio.split('#')]
            train_size = int(len(inout_seq) * data_split_ratio[0])
            val_size = int(len(inout_seq) * (data_split_ratio[0]+data_split_ratio[1])) - train_size
            test_size = int(len(inout_seq)) - train_size - val_size
            train_X, train_y = X[:train_size], y[:train_size]
            val_X, val_y = X[train_size:val_size], y[train_size:val_size]
            test_X, test_y = X[val_size:], y[val_size:]

            # 注意下面的 batch_first=False
            batch_size = cfg.train_batch_size
            train_data = TensorDataset(train_X, train_y)
            train_loader = DataLoader(train_data, shuffle=True, batch_size=batch_size, drop_last=True,
                                      collate_fn=self._collate_fn)
            val_data = TensorDataset(val_X, val_y)
            val_loader = DataLoader(val_data, shuffle=False, batch_size=1, collate_fn=self._collate_fn)
            test_data = TensorDataset(test_X, test_y)
            test_loader = DataLoader(test_data, shuffle=False, batch_size=1, collate_fn=self._collate_fn)

            return train_loader,val_loader, test_loader, self.scaler
        elif self.task_type == 'test' or 'infer':
            # 准备测试数据
            X = torch.FloatTensor(np.array([s[0] for s in inout_seq]))
            y = torch.FloatTensor(np.array([s[1] for s in inout_seq]))

            test_data = TensorDataset(X, y)
            test_loader = DataLoader(test_data, shuffle=False, batch_size=1, collate_fn=self._collate_fn)

            return test_loader, self.scaler




# 模型定义
#################网络结构#################
class LSTM(nn.Module):
    def __init__(self, input_size=10, hidden_layer_size=20, output_size=1):
        super(LSTM,self).__init__()

        self.hidden_layer_size = hidden_layer_size
        self.lstm = nn.LSTM(input_size, hidden_layer_size)
        self.linear = nn.Linear(hidden_layer_size, output_size)
        self.batch_size = cfg.train_batch_size
        self.hidden_cell = (torch.zeros(1, self.batch_size, self.hidden_layer_size),
                            torch.zeros(1, self.batch_size, self.hidden_layer_size))

    def forward(self, input_seq):
        lstm_out, self.hidden_cell = self.lstm(input_seq, self.hidden_cell)
        predictions = self.linear(lstm_out.view(len(input_seq) * self.batch_size, -1))
        # Only return the predictions from the last timestep
        return predictions.view(len(input_seq), self.batch_size, -1)[-1]

    def reset_hidden_state(self,tmp_batch_size):
        ###该函数
        self.batch_size = tmp_batch_size
        self.hidden_cell = (torch.zeros(1, tmp_batch_size, self.hidden_layer_size),
                            torch.zeros(1, tmp_batch_size, self.hidden_layer_size))

class my_run():
    def train(self):
        Dataset = Define_Data(task_type='train')
        Dataset.refresh_df_data(tmp_df_path=os.path.join(cfg.data_input_path,cfg.data_inputfile_name),
                                tmp_df_sheet_name='数据处理',
                                use_lines='[0,3000]')
        train_loader,val_loader,test_loader,scaler = Dataset.get_tensor_data()
        model = LSTM(cfg.in_seq_embeddings, cfg.hidden_features,cfg.out_seq_length).to(cfg.device)
        # 定义损失函数和优化器
        loss_function = nn.MSELoss()
        optimizer = torch.optim.Adam(model.parameters(), lr=cfg.learning_rate, weight_decay=5e-4)

        model.train()
        loss_train_all = []
        for epoch in tqdm(range(cfg.epoch)):
            #训练集
            predictions = []
            test_labels = []
            for seq, labels in train_loader:
                optimizer.zero_grad()
                model.reset_hidden_state(tmp_batch_size=cfg.train_batch_size)  # 重置LSTM隐藏状态
                y_pred = model(seq)
                loss_train = loss_function(torch.squeeze(y_pred), torch.squeeze(labels))
                loss_train_all.append(loss_train.item())
                loss_train.backward()
                optimizer.step()
                predictions.append(y_pred.squeeze().detach().numpy())  # Squeeze to remove extra dimensions
                test_labels.append(labels.squeeze().detach().numpy())
            train_mse,train_mae = self.timeseries_metrics(predictions=predictions,
                                                  test_labels=test_labels,
                                                  scaler=Dataset.scaler)
            #测试val集
            predictions = []
            test_labels = []
            with torch.no_grad():
                for seq, labels in test_loader:
                    model.reset_hidden_state(tmp_batch_size=1)
                    y_test_pred = model(seq)
                    # 保存预测和真实标签
                    predictions.append(y_test_pred.squeeze().detach().numpy())  # Squeeze to remove extra dimensions
                    test_labels.append(labels.squeeze().detach().numpy())
            val_mse,val_mae = self.timeseries_metrics(predictions=predictions,
                                                test_labels=test_labels,
                                                scaler=Dataset.scaler)
            print('Epoch: {:04d}'.format(epoch + 1),
                  'loss_train: {:.4f}'.format(np.mean(loss_train_all)),
                  'mae_train: {:.8f}'.format(train_mae),
                  'mae_val: {:.8f}'.format(val_mae)
                  )

        torch.save(model, os.path.join(cfg.save_model_dir, 'latest.pth'))  # 模型保存
        joblib.dump(Dataset.scaler,os.path.join(cfg.save_model_dir, 'latest_scaler.save')) # 数据缩放比例保存

    def test(self):
        #Create Test Processing
        Dataset = Define_Data(task_type='test')
        Dataset.refresh_df_data(tmp_df_path=os.path.join(cfg.data_input_path,cfg.data_inputfile_name),
                                tmp_df_sheet_name='数据处理',
                                use_lines='[2995,4000]')
        Dataset.scaler = joblib.load(os.path.join(cfg.save_model_dir, 'latest_scaler.save'))
        test_loader,_ = Dataset.get_tensor_data()

        model_path = os.path.join(cfg.save_model_dir, 'latest.pth')
        model = torch.load(model_path, map_location=torch.device(cfg.device))
        model.eval()
        params = sum(p.numel() for p in model.parameters())
        predictions = []
        test_labels = []
        with torch.no_grad():
            for seq, labels in test_loader:
                model.reset_hidden_state(tmp_batch_size=1)
                y_test_pred = model(seq)
                # 保存预测和真实标签
                predictions.append(y_test_pred.squeeze().detach().numpy())  # Squeeze to remove extra dimensions
                test_labels.append(labels.squeeze().detach().numpy())
        _, val_mae = self.timeseries_metrics(predictions=predictions,
                                             test_labels=test_labels,
                                             scaler=Dataset.scaler)
        print('Test set results:',
              'mae_val: {:.8f}'.format(val_mae),
              'params={:.4f}k'.format(params / 1024)
              )

    def BaseTrue_infer(self):
        # Create BaseTrue Infer Processing
        Dataset = Define_Data(task_type='infer')
        Dataset.refresh_df_data(tmp_df_path=os.path.join(cfg.data_input_path, cfg.data_inputfile_name),
                                tmp_df_sheet_name='数据处理',
                                use_lines='[4000,4870]')
        Dataset.scaler = joblib.load(os.path.join(cfg.save_model_dir, 'latest_scaler.save'))
        test_loader, _ = Dataset.get_tensor_data()

        model_path = os.path.join(cfg.save_model_dir, 'latest.pth')
        model = torch.load(model_path, map_location=torch.device(cfg.device))
        model.eval()
        params = sum(p.numel() for p in model.parameters())
        predictions = [] #模型推理值
        test_labels = [] #标签值,可以没有
        with torch.no_grad():
            for seq, labels in test_loader:
                model.reset_hidden_state(tmp_batch_size=1)
                y_test_pred = model(seq)
                # 保存预测和真实标签
                predictions.append(y_test_pred.squeeze().detach().numpy())  # Squeeze to remove extra dimensions
                test_labels.append(labels.squeeze().detach().numpy())

        predictions = np.array(predictions)
        test_labels = np.array(test_labels)
        predictions_rescaled = Dataset.scaler.inverse_transform(predictions.reshape(-1, 1)).flatten()
        test_labels_rescaled = Dataset.scaler.inverse_transform(test_labels.reshape(-1, 1)).flatten()

        pd.DataFrame({'test_labels':test_labels_rescaled,'模型推理值':predictions_rescaled}).to_excel(os.path.join(cfg.save_model_dir,cfg.data_BaseTrue_infer_output_name),index=False)
        print('Infer Ok')

    def BaseSelf_infer(self):
        # Create BaseSelf Infer Processing
        Dataset = Define_Data(task_type='infer')
        Dataset.refresh_df_data(tmp_df_path=os.path.join(cfg.data_input_path, cfg.data_inputfile_name),
                                tmp_df_sheet_name='数据处理',
                                use_lines='[4000,4870]')
        Dataset.scaler = joblib.load(os.path.join(cfg.save_model_dir, 'latest_scaler.save'))
        test_loader, _ = Dataset.get_tensor_data()
        initial_input, labels = next(iter(test_loader))

        model_path = os.path.join(cfg.save_model_dir, 'latest.pth')
        model = torch.load(model_path, map_location=torch.device(cfg.device))
        model.eval()
        params = sum(p.numel() for p in model.parameters())
        predictions = [] #模型推理值
        with torch.no_grad():
            for _ in range(cfg.num_predictions):

                model.reset_hidden_state(tmp_batch_size=1)
                y_test_pred = model(initial_input)
                # 将预测结果转换为适合再次输入模型的形式
                next_input = torch.cat((initial_input[1:, ...], y_test_pred.unsqueeze(-1)), dim=0)
                initial_input = next_input
                # 保存预测和真实标签
                predictions.append(y_test_pred.squeeze().item())  # Squeeze to remove extra dimensions

        predictions_rescaled = Dataset.scaler.inverse_transform(np.array(predictions).reshape(-1, 1)).flatten()

        pd.DataFrame({'模型推理值': predictions_rescaled}).to_excel(os.path.join(cfg.save_model_dir,cfg.data_BaseSelf_infer_output_name), index=False)
        print('Infer Ok')

    def timeseries_metrics(self,predictions,test_labels,scaler):
        # 反向缩放预测和标签值
        predictions = np.array(predictions)
        test_labels = np.array(test_labels)

        # 此处假设predictions和test_labels是一维数组,如果不是,你可能需要调整reshape的参数
        predictions_rescaled = scaler.inverse_transform(predictions.reshape(-1, 1)).flatten()
        test_labels_rescaled = scaler.inverse_transform(test_labels.reshape(-1, 1)).flatten()

        # 计算MSE和MAE
        mse = mean_squared_error(test_labels_rescaled, predictions_rescaled)
        mae = mean_absolute_error(test_labels_rescaled, predictions_rescaled)
        # print(f"Test MSE on original scale: {mse}")
        # print(f"Test MAE on original scale: {mae}")
        return mse,mae

if __name__ == '__main__':
    myrun = my_run()
    if cfg.istrain == True:
        myrun.train()
    if cfg.istest == True:
        myrun.test()
    if cfg.BaseTrue_infer == True:
        myrun.BaseTrue_infer()
    if cfg.BaseSelf_infer == True:
        myrun.BaseSelf_infer()

 四、结果展示

   本文代码,配置了两种预测模式,第一种,BaseTrue_infer:根据真实数据预测下一个点,然后循环用的真实数据;第二种,BaseSelf_infer:根据预测数据自回归预测下一个点,然后循环用的预测数据。实际用的一般都是第二种才有实用价值,当然本文时序预测的训练模式没有采用长距离自动纠偏的trick,所以第二种预测就直接坍塌了。后续可以研究探讨长时间预测如何进行。下面贴上在"五粮液"股价收盘价上的实验结果。

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

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

相关文章

以“美”为鉴,探寻香港比特币现货ETF的未来发展

出品&#xff5c;欧科云链研究院 作者&#xff5c;Hedy Bi 根据The Block于1月29日的报道&#xff0c;嘉实国际成为了首家向香港证监会提交比特币现货ETF申请的机构。早在去年12月22日&#xff0c;香港证监会发布了《有关证监会认可基金投资虚拟资产的通函》&#xff0c;明确…

突破瓶颈,提升开发效率:Spring框架进阶与最佳实践-IOC

IOC相关内容 1.1 bean基础配置1.1.1 bean基础配置(id与class)1.1.2 bean的name属性步骤1&#xff1a;配置别名步骤2:根据名称容器中获取bean对象步骤3:运行程序 1.1.3 bean作用范围scope配置1.1.3.1 验证IOC容器中对象是否为单例验证思路具体实现 1.1.3.2 配置bean为非单例1.1.…

C++文件操作(1)

C文件操作 1.文本的写入及读取文本文件写入文本文件读取 2.二进制文件的写入及读取二进制文件写入二进制文件读取 3.小结 C也有处理文件的能力&#xff0c;其功能实现依赖文件流。文件流是C中用来处理文件输入输出的一种流类。文件流可以用于从文件中读取数据或将数据写入到文件…

开发工具git分支冲突解决

在团队协作的软件开发过程中&#xff0c;Git是一款广泛使用的版本控制系统。然而&#xff0c;当多个开发者同时修改同一文件或代码段时&#xff0c;就会产生分支冲突。解决这些冲突需要仔细的协调和技术知识。本篇博客将介绍Git分支冲突的解决方法&#xff0c;以及开发工具和最…

四工序开料机可以加工什么产品

四工序开料机是木工机械设备中一款重要设备&#xff0c;该设备主要的功能是开料、打孔、拉槽等&#xff0c;一机多用&#xff0c;凭借多功能的加工效果&#xff0c;实现高速加工的效果&#xff0c;那么这样的设备可以加工什么类型的产品呢&#xff1f;大家对此了解多少呢&#…

idea报错 :(java: 找不到符号)

java: 找不到符号 符号: 变量 adminService 位置: 类 com.example.controller.WebController 查到网上一个办法&#xff1a;因为项目是maven&#xff1a;先点clean在点package

anaconda离线安装包的方法

当设备没有网络时&#xff0c;可以使用有网络的设备先下载所需安装包&#xff0c;然后离线拷贝到需要安装的设备&#xff0c;最后安装。 一. 下载所需安装包 下载命令&#xff1a;使用pip download。详细描述参见pip download -h 以"blind-watermark"为例。 pip …

一站式在线协作办公软件ONLYOFFICE,协作更便捷

1、ONLYOFFICE是什么&#xff1f; ONLYOFFICE是一款功能强大的在线协作办公软件&#xff0c;可以创建编辑Word文档、Excel电子表格&#xff0c;PowerPoint&#xff08;PPT&#xff09;演示文稿、Forms表单等多种文件。ONLYOFFICE支持多个平台&#xff0c;无论使用的是 Windows、…

真机调试,微信小程序,uniapp项目在微信开发者工具中真机调试,手机和电脑要连同一个wifi,先清空缓存,页面从登录页进入,再点真机调试,这样就不会报错了

微信小程序如何本地进行真机调试&#xff1f;_unity生成的微信小程序怎么在电脑上真机测试-CSDN博客 微信小程序 真机调试 注意事项 uniapp项目在微信开发者工具中真机调试&#xff0c;手机和电脑要连同一个wifi&#xff0c;先清空缓存&#xff0c;页面从登录页进入&#xf…

怎么保护U盘数据?如何提高U盘的安全性?

U盘作为常用的移动储存设备&#xff0c;能够帮我们存储大量数据。而为了避免数据泄露&#xff0c;我们需要采用专业的方式提高U盘的安全性。那么&#xff0c;怎么保护U盘数据呢&#xff1f;下面我们就一起来了解一下。 如何提高U盘的安全性&#xff1f; 提高U盘数据安全性的方…

3DMAX一键生成样条线纤维插件使用方法

3DMAX一键生成样条线纤维插件使用教程 3DMAX一键生成样条线纤维插件&#xff0c;是一个强大的脚本工具&#xff0c;用于围绕选定的样条线路径创建纤维。它有许多设置用于微调纤维的形状和材质。 【适用版本】 3dMax2010 – 2024&#xff08;不仅限于此范围&#xff09; 【安装…

Rust基础篇之注释、函数

&#x1f339;作者主页&#xff1a;青花锁 &#x1f339;简介&#xff1a;Java领域优质创作者&#x1f3c6;、Java微服务架构公号作者&#x1f604; &#x1f339;简历模板、学习资料、面试题库、技术互助 &#x1f339;文末获取联系方式 &#x1f4dd; 往期专栏回顾 专栏描述…

Wireshark网络协议分析 - UDP协议

在我的博客阅读本文 文章目录 1. 基础2. 实战2.1. 用Go写一个简单的UDP服务器与客户端2.2. Wireshark抓包分析 3. UDP与TCP的区别4. 参考资料 1. 基础 UDP包的数据结构&#xff1a; 2. 实战 2.1. 用Go写一个简单的UDP服务器与客户端 我们这里使用Golang写了一个简单的9830端…

appsmith安装手记:4.Sql server数据库容器安装

appsmith安装好&#xff0c;那就可以看是练练手。 数据当然是来自数据库&#xff0c;那就连接局域网中现成的一台数据库服务器试试&#xff0c;但是连接数据库的时候一直错误。 找到/home/appsmith/backend 目录下的日志&#xff0c;看到了错误&#xff1a; [rootlocalhost bac…

【HarmonyOS应用开发】ArkUI 开发框架-基础篇-第二部分(八)

八、Column&Row组件的使用 概述 一个丰富的页面需要很多组件组成&#xff0c;那么&#xff0c;我们如何才能让这些组件有条不紊地在页面上布局呢&#xff1f;这就需要借助容器组件来实现。 容器组件是一种比较特殊的组件&#xff0c;它可以包含其他的组件&#xff0c;而…

Qt 调用系统键盘

Wow64DisableWow64FsRedirection(&pvoid) 函数用于禁用 32 位 Windows 程序对文件系统重定向的支持。它将禁用文件系统重定向&#xff0c;以便在运行 32 位应用程序时&#xff0c;可以访问 64 位系统目录。pvoid 是一个指向先前启用的文件系统重定向状态的指针。 构建了要…

《动手学深度学习(PyTorch版)》笔记4.8

注&#xff1a;书中对代码的讲解并不详细&#xff0c;本文对很多细节做了详细注释。另外&#xff0c;书上的源代码是在Jupyter Notebook上运行的&#xff0c;较为分散&#xff0c;本文将代码集中起来&#xff0c;并加以完善&#xff0c;全部用vscode在python 3.9.18下测试通过。…

文本三剑客之grep

目录 一、正则表达式 1、什么是正则表达式 2、元字符 3、扩展正则表达式元字符 二、grep 一、正则表达式 1、什么是正则表达式 REGEXP&#xff1a; Regular Expressions&#xff0c;由一类特殊字符及文本字符所编写的模式&#xff0c;其中有些字符&#xff08;元字符&#…

DevOps落地笔记-04|看板方法:成员工作内容清楚明白方法

上一讲主要介绍了用户故事以及如何通过讲好用户故事解决团队沟通的问题&#xff0c;争取达成共识。当团队都理解了用户需求之后&#xff0c;就进入到后续的产品设计、代码开发、功能测试、直到生产部署等环节了。作为软件从业人员都知道&#xff0c;后续的步骤不太可能一帆风顺…

初探分布式链路追踪

本篇文章&#xff0c;主要介绍应用如何正确使用日志系统&#xff0c;帮助用户从依赖、输出、清理、问题排查、报警等各方面全面掌握。 可观测性 可观察性不单是一套理论框架&#xff0c;而且并不强制具体的技术规格。其核心在于鼓励团队内化可观察性的理念&#xff0c;并确保由…