ChatGLM3微调实战:LLaMA-Factory中Segmentation fault报错的5种排查方法

ChatGLM3微调实战:LLaMA-Factory中Segmentation fault报错的5种排查方法

最近在折腾LLaMA-Factory微调ChatGLM3,相信不少朋友都遇到过那个让人头疼的“Segmentation fault (core dumped)”报错。这个错误就像个幽灵,总是在你最意想不到的时候出现,然后留下一堆core dump文件让你无从下手。特别是当你确认模型下载正确、CUDA环境也没问题,但训练命令一执行就崩溃时,那种挫败感真是难以言表。

我花了整整一周时间跟这个错误较劲,从Ubuntu 18.04折腾到20.04,从PyTorch版本换到Hugging Face datasets库的各种组合,最终总结出了5种行之有效的排查方法。这些方法不仅适用于LLaMA-Factory框架,对于其他基于PyTorch的深度学习项目遇到类似问题也有参考价值。今天我就把这些实战经验分享出来,希望能帮你少走弯路。

1. 理解Segmentation fault的本质与常见触发场景

在开始具体排查之前,我们得先搞清楚Segmentation fault到底是什么。简单来说,这是程序试图访问它没有权限访问的内存区域时,操作系统发出的“死刑判决”。在Linux系统中,每个进程都有自己的虚拟地址空间,当程序指针越界、访问已释放的内存或者尝试写入只读内存时,内核就会发送SIGSEGV信号终止进程。

在LLaMA-Factory微调ChatGLM3的场景下,Segmentation fault通常出现在几个特定环节:

  • 数据加载阶段:最常见的就是在调用datasets.load_dataset()时崩溃,日志显示“Loading dataset...”后就没了下文
  • 模型初始化阶段:加载预训练权重时,特别是当模型文件损坏或格式不匹配时
  • 训练循环开始:第一个batch的前向传播或反向传播过程中
  • 内存分配失败:GPU显存或系统内存不足,但错误表现可能被包装成Segmentation fault

注意:Segmentation fault本身只是一个症状,不是病因。就像发烧一样,可能是感冒、流感或者更严重的问题引起的。

下面这个表格整理了我在不同项目中遇到的Segmentation fault触发场景和初步判断线索:

触发阶段典型日志特征可能原因排查优先级
数据加载“Loading dataset...”后立即崩溃datasets库版本冲突、数据文件损坏、Python扩展模块问题
模型加载“Loading model...”或特定层名后崩溃模型文件损坏、PyTorch版本不匹配、CUDA/cuDNN问题
训练开始第一个batch的前向传播中崩溃输入数据格式错误、自定义层实现bug、混合精度配置问题
随机崩溃训练过程中不定时崩溃内存泄漏、竞态条件、硬件不稳定

理解这些模式能帮你快速定位问题方向。比如,如果错误总是发生在datasets.load_dataset()调用时,那么问题很可能出在数据加载相关的依赖上,而不是模型本身。

2. 环境诊断:从基础依赖到版本兼容性

环境问题是最常见也是最容易被忽视的Segmentation fault根源。很多开发者只检查了torch.cuda.is_available()返回True就以为万事大吉,但实际上CUDA可用只是最低要求。

2.1 系统级依赖检查

首先,我们需要确认系统层面的依赖是否完整。深度学习框架依赖很多底层的C/C++库,缺少任何一个都可能导致Segmentation fault。

# 检查关键系统库
ldd --version
gcc --version
g++ --version
make --version

# 检查CUDA驱动和运行时
nvidia-smi
nvcc --version

# 检查glibc版本(重要!)
ldd --version | grep ldd

Ubuntu 18.04到20.04的切换之所以能解决问题,很多时候是因为glibc版本的升级。某些Python包编译时依赖较新版本的glibc,在旧系统上运行就会崩溃。

2.2 Python环境深度诊断

创建一个专门的环境诊断脚本,系统性地检查所有关键依赖:

#!/usr/bin/env python3
import torch
import sys
import subprocess
import platform

print("=" * 60)
print("Python环境诊断报告")
print("=" * 60)

# Python信息
print(f"Python版本: {sys.version}")
print(f"Python路径: {sys.executable}")
print(f"平台信息: {platform.platform()}")

# PyTorch信息
print(f"\nPyTorch版本: {torch.__version__}")
print(f"CUDA可用: {torch.cuda.is_available()}")
if torch.cuda.is_available():
    print(f"CUDA版本: {torch.version.cuda}")
    print(f"cuDNN版本: {torch.backends.cudnn.version()}")
    print(f"GPU设备: {torch.cuda.get_device_name(0)}")
    print(f"GPU数量: {torch.cuda.device_count()}")

# 检查关键包的版本
packages = ['transformers', 'datasets', 'accelerate', 'peft', 'bitsandbytes']
for pkg in packages:
    try:
        exec(f"import {pkg}")
        version = eval(f"{pkg}.__version__")
        print(f"{pkg}版本: {version}")
    except ImportError:
        print(f"{pkg}: 未安装")
    except AttributeError:
        print(f"{pkg}: 版本信息不可用")

# 测试基础CUDA功能
print("\n" + "=" * 60)
print("CUDA功能测试")
print("=" * 60)

if torch.cuda.is_available():
    try:
        # 测试张量创建和计算
        x = torch.randn(100, 100).cuda()
        y = torch.randn(100, 100).cuda()
        z = torch.mm(x, y)
        print("✓ 基础CUDA计算测试通过")
        
        # 测试内存分配
        large_tensor = torch.randn(1000, 1000, 100).cuda()
        del large_tensor
        torch.cuda.empty_cache()
        print("✓ 大内存分配/释放测试通过")
        
    except Exception as e:
        print(f"✗ CUDA测试失败: {e}")
else:
    print("✗ CUDA不可用")

print("\n诊断完成")

运行这个脚本,你会得到一份完整的环境报告。重点关注:

  • PyTorch CUDA版本与系统CUDA驱动版本是否匹配
  • 关键包(特别是datasets)的版本是否在兼容范围内
  • 基础CUDA功能测试是否通过

2.3 版本兼容性矩阵

根据我的经验,以下版本组合在LLaMA-Factory微调ChatGLM3时最为稳定:

组件推荐版本最低版本已知问题版本
PyTorch2.1.0+cu1182.0.01.x版本可能缺少某些特性
Transformers4.35.04.30.04.28.x与ChatGLM3有兼容问题
Datasets2.14.02.10.02.15.0+在某些系统上有bug
Accelerate0.24.00.20.0
PEFT0.6.00.5.0
Python3.103.83.11可能有兼容问题

如果环境诊断发现问题,建议使用conda或venv创建全新的虚拟环境,按照上述兼容性矩阵重新安装。

3. 数据加载层深度排查

从原始文章的描述来看,错误发生在datasets.load_dataset()调用时,这是非常典型的案例。数据加载看似简单,实则涉及文件I/O、内存映射、多进程处理等多个复杂环节。

3.1 最小化复现代码

首先,我们需要创建一个最小化的复现代码,隔离问题:

# test_dataset_loading.py
from datasets import load_dataset
import traceback
import sys

def test_load_dataset():
    """测试datasets库的基本加载功能"""
    print("测试1: 加载本地JSON文件")
    try:
        # 使用一个极简的测试数据
        test_data = {
            "instruction": ["测试指令"],
            "input": [""],
            "output": ["测试输出"]
        }
        
        import json
        import tempfile
        import os
        
        # 创建临时文件
        with tempfile.NamedTemporaryFile(mode='w', suffix='.json', delete=False) as f:
            json.dump(test_data, f)
            temp_path = f.name
        
        print(f"临时文件路径: {temp_path}")
        
        # 尝试加载
        dataset = load_dataset('json', data_files=temp_path)
        print(f"✓ 数据集加载成功,样本数: {len(dataset['train'])}")
        
        # 清理
        os.unlink(temp_path)
        
    except Exception as e:
        print(f"✗ 加载失败: {e}")
        traceback.print_exc()
        return False
    
    print("\n测试2: 加载远程数据集(小规模)")
    try:
        # 尝试加载一个小的远程数据集
        dataset = load_dataset('glue', 'cola', split='train[:10]')
        print(f"✓ 远程数据集加载成功,样本数: {len(dataset)}")
    except Exception as e:
        print(f"✗ 远程加载失败: {e}")
        traceback.print_exc()
        return False
    
    return True

if __name__ == "__main__":
    print("=" * 60)
    print("Datasets库加载测试")
    print("=" * 60)
    
    success = test_load_dataset()
    
    if success:
        print("\n✓ 所有测试通过")
        sys.exit(0)
    else:
        print("\n✗ 测试失败")
        sys.exit(1)

运行这个测试脚本:

python test_dataset_loading.py

如果这个脚本也触发Segmentation fault,那么问题肯定出在datasets库或其依赖上。

3.2 深入datasets库内部

当确定问题在datasets库时,我们需要更深入地排查。datasets库底层使用Apache Arrow进行高效的数据处理,而Arrow依赖很多C++扩展模块。

检查Arrow的安装情况:

import pyarrow as pa
import pyarrow.dataset as ds
import pyarrow.parquet as pq

print(f"PyArrow版本: {pa.__version__}")
print(f"Arrow编译选项: {pa.cpp_build_info}")

# 测试Arrow基本功能
try:
    table = pa.table({'col1': [1, 2, 3], 'col2': ['a', 'b', 'c']})
    print(f"✓ Arrow表格创建成功: {table.shape}")
    
    # 测试内存操作
    buffer = pa.py_buffer(b'test buffer')
    print(f"✓ 缓冲区操作成功")
    
except Exception as e:
    print(f"✗ Arrow测试失败: {e}")

常见的数据加载问题及解决方案:

  1. 内存映射问题:datasets库默认使用内存映射文件来高效加载大文件,但在某些文件系统(如NFS)或配置下可能有问题
# 尝试禁用内存映射
dataset = load_dataset('json', 
                      data_files='your_data.json',
                      keep_in_memory=True)  # 强制加载到内存
  1. 多进程问题:数据预处理默认使用多进程,可能触发Segmentation fault
# 单进程加载
import os
os.environ["TOKENIZERS_PARALLELISM"] = "false"

# 或者在load_dataset时指定
dataset = load_dataset('json', 
                      data_files='your_data.json',
                      num_proc=1)  # 单进程
  1. 文件编码问题:特别是Windows系统创建的文件可能在Linux上有编码问题
# 检查文件编码
file -i your_data.json
# 转换编码(如果需要)
iconv -f utf-8 -t utf-8 your_data.json > your_data_fixed.json

3.3 系统级调试工具

当Python层面的排查无法解决问题时,我们需要动用系统级的调试工具。

使用gdb调试Python进程:

# 安装调试符号(如果可用)
sudo apt-get install python3-dbg

# 使用gdb运行Python脚本
gdb -ex r --args python src/train_bash.py --your-arguments

# 在gdb中,当Segmentation fault发生时
bt  # 查看完整的调用栈
info registers  # 查看寄存器状态
x/10i $pc  # 查看崩溃位置的汇编指令

分析core dump文件:

如果系统启用了core dump,我们可以分析崩溃时的内存状态:

# 首先确保core dump已启用
ulimit -c unlimited
echo "core.%e.%p.%t" | sudo tee /proc/sys/kernel/core_pattern

# 运行会崩溃的程序
python train_script.py

# 程序崩溃后,使用gdb分析core文件
gdb python core.python.*
bt full  # 查看完整栈跟踪

使用strace跟踪系统调用:

strace -f -o strace.log python src/train_bash.py --your-arguments

分析strace.log文件,关注以下系统调用:

  • mmap/munmap:内存映射相关操作
  • brk:堆内存分配
  • 文件相关的open/read/close
  • 信号处理相关的sigaction/kill

4. 内存与硬件问题排查

Segmentation fault有时不是软件bug,而是硬件或系统配置问题。特别是在使用大模型时,内存压力非常大。

4.1 内存诊断工具

监控内存使用情况:

# 安装监控工具
sudo apt-get install htop numactl

# 实时监控
htop

# 查看NUMA配置(多CPU系统)
numactl --hardware

# 查看内存详细信息
cat /proc/meminfo
free -h

使用Python内存分析工具:

import psutil
import resource
import torch

def print_memory_info():
    """打印详细的内存使用信息"""
    process = psutil.Process()
    
    print("=" * 60)
    print("内存使用报告")
    print("=" * 60)
    
    # 系统内存
    sys_mem = psutil.virtual_memory()
    print(f"系统总内存: {sys_mem.total / 1024**3:.2f} GB")
    print(f"系统已用内存: {sys_mem.used / 1024**3:.2f} GB")
    print(f"系统可用内存: {sys_mem.available / 1024**3:.2f} GB")
    print(f"内存使用率: {sys_mem.percent}%")
    
    # 进程内存
    mem_info = process.memory_info()
    print(f"\n进程RSS: {mem_info.rss / 1024**3:.2f} GB")
    print(f"进程VMS: {mem_info.vms / 1024**3:.2f} GB")
    
    # GPU内存
    if torch.cuda.is_available():
        print(f"\nGPU内存使用:")
        for i in range(torch.cuda.device_count()):
            alloc = torch.cuda.memory_allocated(i) / 1024**3
            cached = torch.cuda.memory_reserved(i) / 1024**3
            total = torch.cuda.get_device_properties(i).total_memory / 1024**3
            print(f"  GPU {i}: 已分配 {alloc:.2f} GB / 缓存 {cached:.2f} GB / 总计 {total:.2f} GB")
    
    # 资源限制
    soft, hard = resource.getrlimit(resource.RLIMIT_AS)
    print(f"\n虚拟内存限制: 软限制={soft}, 硬限制={hard}")

# 在关键位置调用
print_memory_info()

4.2 内存相关配置优化

调整系统内存配置:

# 增加overcommit设置(允许更多内存分配)
echo 1 | sudo tee /proc/sys/vm/overcommit_memory

# 调整swappiness(减少交换,但需要足够物理内存)
echo 10 | sudo tee /proc/sys/vm/swappiness

# 清理页面缓存(在内存紧张时)
echo 3 | sudo tee /proc/sys/vm/drop_caches

Python内存管理配置:

import gc
import torch

# 启用更积极的垃圾回收
gc.set_threshold(700, 10, 10)

# 配置PyTorch内存管理
torch.cuda.empty_cache()
torch.cuda.memory_summary(device=None, abbreviated=False)

# 设置最大分割大小(减少内存碎片)
torch.cuda.set_per_process_memory_fraction(0.8)  # 使用80%的GPU内存

4.3 硬件诊断

硬件问题(特别是内存故障)也可能导致Segmentation fault。

内存测试:

# 安装内存测试工具
sudo apt-get install memtester

# 测试系统内存(需要root权限)
sudo memtester 1G 3  # 测试1GB内存,循环3次

# 或者使用更全面的memtest86+
# 需要从USB启动,无法在运行中的系统上执行

GPU诊断:

# 全面GPU测试
nvidia-smi -q  # 查询GPU详细信息

# 运行CUDA样本测试(需要安装CUDA Samples)
cd /usr/local/cuda/samples/1_Utilities/deviceQuery
sudo make
./deviceQuery

# 测试GPU计算
cd /usr/local/cuda/samples/1_Utilities/bandwidthTest
sudo make
./bandwidthTest

5. 高级调试技巧与预防措施

当常规方法都无法解决问题时,我们需要更高级的调试技巧。

5.1 使用LLDB进行Python调试

LLDB是比GDB更现代的调试器,对Python支持更好:

# 安装lldb和python插件
sudo apt-get install lldb python3-lldb

# 启动lldb调试
lldb python
(lldb) run src/train_bash.py --your-arguments

# 崩溃时自动断点
(lldb) settings set target.stop-on-sharedlibrary-events 1
(lldb) run

# 查看Python回溯
(lldb) script import sys; sys.path.insert(0, '/usr/lib/python3.10/dist-packages')
(lldb) command script import lldb
(lldb) bt

5.2 使用AddressSanitizer检测内存错误

AddressSanitizer是Google开发的内存错误检测工具,能发现很多常规测试难以发现的问题:

# 重新编译Python with ASan
sudo apt-get install libasan6
export CC="gcc -fsanitize=address -fno-omit-frame-pointer"
export CXX="g++ -fsanitize=address -fno-omit-frame-pointer"

# 下载Python源码
wget https://www.python.org/ftp/python/3.10.0/Python-3.10.0.tgz
tar xzf Python-3.10.0.tgz
cd Python-3.10.0

# 配置和编译
./configure --prefix=/usr/local/python-asan --enable-optimizations
make -j$(nproc)
sudo make install

# 使用ASan版本的Python运行程序
/usr/local/python-asan/bin/python src/train_bash.py --your-arguments

ASan会在内存错误发生时提供详细的诊断信息,包括:

  • 堆栈溢出
  • 使用释放后的内存
  • 双重释放
  • 内存泄漏

5.3 预防性编程实践

最好的调试是不需要调试。通过良好的编程实践,可以避免很多Segmentation fault问题。

安全的内存访问模式:

# 不安全的做法
def unsafe_access(data, index):
    return data[index]  # 可能越界

# 安全的做法
def safe_access(data, index):
    if index < 0 or index >= len(data):
        raise IndexError(f"Index {index} out of bounds for data of length {len(data)}")
    return data[index]

# 或者使用更Pythonic的方式
def pythonic_access(data, index):
    try:
        return data[index]
    except IndexError:
        # 提供有意义的错误信息
        raise IndexError(f"Index {index} out of bounds") from None

资源管理的最佳实践:

from contextlib import contextmanager
import torch

@contextmanager
def gpu_memory_context(device_id=0):
    """上下文管理器,确保GPU内存正确清理"""
    try:
        yield
    finally:
        torch.cuda.synchronize(device_id)
        torch.cuda.empty_cache()
        
        # 记录内存使用情况
        allocated = torch.cuda.memory_allocated(device_id) / 1024**2
        reserved = torch.cuda.memory_reserved(device_id) / 1024**2
        print(f"GPU {device_id}: 清理后内存 - 已分配 {allocated:.1f} MB, 保留 {reserved:.1f} MB")

# 使用示例
with gpu_memory_context():
    # 你的训练代码
    model.train()
    for batch in dataloader:
        # 训练逻辑
        pass

配置检查与验证:

import yaml
import json
from pathlib import Path

class ConfigValidator:
    """配置验证器,防止配置错误导致运行时崩溃"""
    
    def __init__(self, config_path):
        self.config_path = Path(config_path)
        self.schema = self._load_schema()
        
    def _load_schema(self):
        """加载配置模式定义"""
        return {
            'required': ['model_name', 'dataset', 'training'],
            'model_name': {
                'type': str,
                'allowed': ['chatglm3-6b', 'chatglm3-12b', 'custom']
            },
            'batch_size': {
                'type': int,
                'min': 1,
                'max': 32
            },
            # 更多验证规则...
        }
    
    def validate(self):
        """验证配置文件"""
        if not self.config_path.exists():
            raise FileNotFoundError(f"配置文件不存在: {self.config_path}")
        
        # 加载配置
        if self.config_path.suffix == '.yaml':
            with open(self.config_path) as f:
                config = yaml.safe_load(f)
        elif self.config_path.suffix == '.json':
            with open(self.config_path) as f:
                config = json.load(f)
        else:
            raise ValueError(f"不支持的配置文件格式: {self.config_path.suffix}")
        
        # 验证必需字段
        for field in self.schema['required']:
            if field not in config:
                raise ValueError(f"缺少必需字段: {field}")
        
        # 验证字段类型和取值范围
        self._validate_fields(config)
        
        return config
    
    def _validate_fields(self, config):
        """验证各个字段"""
        for field, rules in self.schema.items():
            if field == 'required':
                continue
                
            if field in config:
                value = config[field]
                
                # 类型检查
                if 'type' in rules and not isinstance(value, rules['type']):
                    raise TypeError(f"字段 {field} 应为 {rules['type']} 类型,实际为 {type(value)}")
                
                # 取值范围检查
                if 'min' in rules and value < rules['min']:
                    raise ValueError(f"字段 {field} 的值 {value} 小于最小值 {rules['min']}")
                
                if 'max' in rules and value > rules['max']:
                    raise ValueError(f"字段 {field} 的值 {value} 大于最大值 {rules['max']}")
                
                # 允许值检查
                if 'allowed' in rules and value not in rules['allowed']:
                    raise ValueError(f"字段 {field} 的值 {value} 不在允许的范围内: {rules['allowed']}")

# 使用示例
validator = ConfigValidator('config.yaml')
try:
    config = validator.validate()
    print("✓ 配置验证通过")
except Exception as e:
    print(f"✗ 配置错误: {e}")
    # 提供修复建议
    self._suggest_fixes(e)

5.4 监控与日志增强

完善的监控和日志能帮助快速定位问题:

import logging
import sys
from logging.handlers import RotatingFileHandler

def setup_logging(log_file='training.log'):
    """设置详细的日志记录"""
    
    # 创建logger
    logger = logging.getLogger()
    logger.setLevel(logging.DEBUG)
    
    # 文件处理器(轮转,避免日志文件过大)
    file_handler = RotatingFileHandler(
        log_file, 
        maxBytes=10*1024*1024,  # 10MB
        backupCount=5
    )
    file_handler.setLevel(logging.DEBUG)
    
    # 控制台处理器
    console_handler = logging.StreamHandler(sys.stdout)
    console_handler.setLevel(logging.INFO)
    
    # 格式化器
    formatter = logging.Formatter(
        '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
    )
    file_handler.setFormatter(formatter)
    console_handler.setFormatter(formatter)
    
    # 添加处理器
    logger.addHandler(file_handler)
    logger.addHandler(console_handler)
    
    return logger

# 在代码关键点添加详细日志
logger = setup_logging()

def load_data_safely(data_path):
    """安全加载数据,带详细日志"""
    logger.info(f"开始加载数据: {data_path}")
    
    try:
        # 记录内存状态
        import psutil
        process = psutil.Process()
        mem_before = process.memory_info().rss / 1024**2
        
        # 加载数据
        dataset = load_dataset('json', data_files=data_path)
        
        mem_after = process.memory_info().rss / 1024**2
        logger.info(f"数据加载完成,内存使用: {mem_after - mem_before:.1f} MB")
        logger.info(f"数据集大小: {len(dataset['train'])} 样本")
        
        return dataset
        
    except Exception as e:
        logger.error(f"数据加载失败: {e}", exc_info=True)
        raise

# 添加信号处理器,捕获崩溃信息
import signal
import traceback

def signal_handler(signum, frame):
    """处理信号,记录崩溃信息"""
    logger.critical(f"收到信号 {signum},程序即将终止")
    logger.critical("当前调用栈:")
    for line in traceback.format_stack(frame):
        logger.critical(line.strip())
    
    # 记录内存状态
    import torch
    if torch.cuda.is_available():
        for i in range(torch.cuda.device_count()):
            alloc = torch.cuda.memory_allocated(i) / 1024**2
            logger.critical(f"GPU {i} 内存: {alloc:.1f} MB")
    
    # 正常退出
    sys.exit(1)

# 注册信号处理器
signal.signal(signal.SIGSEGV, signal_handler)  # Segmentation fault
signal.signal(signal.SIGABRT, signal_handler)  # 异常终止
signal.signal(signal.SIGILL, signal_handler)   # 非法指令

这些方法虽然不能保证完全避免Segmentation fault,但能大大减少发生的概率,并在问题发生时提供足够的信息进行诊断。实际项目中,我通常会结合多种方法,从最简单的环境检查开始,逐步深入到系统级调试。大多数情况下,问题都能在前三种方法中找到解决方案。只有在极少数情况下,才需要动用ASan或LLDB这样的高级工具。

内容概要:本文系统研究了基于模型预测控制(MPC)与滚动时域估计(MHE)集成的控制方法,旨在实现动态系统的高精度目标点镇定。通过构建MPC与MHE的协同框架,利用MHE对系统状态进行实时、高效的滚动优化估计,克服传感器测量噪声与初始状态不确定的影响,并将估计结果反馈至MPC控制器,实现对未来控制序列的滚动优化,从而提升系统在复杂干扰和不确定性环境下的镇定性能与鲁棒性。研究涵盖算法原理推导、数学建模、仿真设计与验证全过程,提供了完整的Matlab代码实现,充分展示了该集成策略在状态估计与反馈控制协同优化方面的优越性。; 适合人群:具备自动控制理论基础和Matlab编程能力,从事控制工程、自动化、机器人、航空航天或相关领域研究的研发人员及研究生。; 使用场景及目标:①应用于移动机器人、无人机、自动驾驶等需要高精度状态反馈的自主系统目标点镇定任务;②解决系统状态不可直接测量或受强噪声干扰时的状态估计与反馈控制耦合问题;③为先进预测控制与状态估计算法的联合设计与工程实现提供可复现的技术范例与实践指导; 阅读建议:建议读者结合Matlab代码逐模块分析算法实现细节,重点关注MHE状态估计与MPC控制指令生成之间的数据交互逻辑与时序配合,并尝试在不同非线性系统模型上进行迁移测试,以深入理解MPC-MHE集成机制的核心优势与调参规律。
代码转载自:https://pan.quark.cn/s/a4b39357ea24 WeixinBot star this repo fork this repo python 网页版微信API,包含终端版微信及微信机器人 Contents Demo Web Weixin Pipeline Web Weixin API Discussion Group Recent Update Demo 为了确保能正常运行示例脚本,请安装所需的第三方包。 注:下面演示的图片与功能可能不是最新的,具体请看源码。 按照操作指示在手机微信上扫描二维码然后登录,你可以选择是否开启自动回复模式。 2 开启自动回复模式后,如果接收到的是文字消息就会自动回复,包括群消息。 3 名片,链接,动画表情和地址位置消息。 4 5 网页版上有的功能目前基本上都能支持。 Web Weixin Pipeline Web Weixin API 登录 返回数据(String): 注:这里的appid就是在微信开放平台注册的应用的AppID。 网页版微信有两个AppID,早期的是,在微信客户端上显示为应用名称为;现在用的是,显示名称为。 返回数据(String): 返回数据(String): 返回数据(XML): 微信初始化 返回数据(JSON): 返回数据(JSON): 获取联系人信息 返回数据(JSON): 返回数据(JSON)同上 同步刷新 返回数据(String): 返回数据(JSON): 消息接口 返回数据(JSON): 返回数据(JSON): 发送表情 图片接口 多媒体接口 账号类型 消息类型 消息一般格式: 微信初始化消息 文本消息 图片消息 小视频消息 地理位置消息 名片消息 语音消息 动画表...
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值