当前位置:首页>python>大模型开发入门第六讲:Python 函数,把大模型训练逻辑 “打包复用”!

大模型开发入门第六讲:Python 函数,把大模型训练逻辑 “打包复用”!

  • 2026-10-02 10:27:18
大模型开发入门第六讲:Python 函数,把大模型训练逻辑 “打包复用”!
上一篇我们学会了用容器高效管理数据,今天要攻克的函数,是大模型工程化开发的核心 —— 把重复的数据预处理、损失计算、训练循环等逻辑 “打包” 成函数,不用每次写重复代码,还能让项目结构更清晰、调试更方便!大模型开发动辄上千行代码,函数就是帮你 “化繁为简” 的利器

一、函数基础:定义与调用

函数就像一个 “黑盒子”,你给它输入(参数),它给你输出(返回值),内部逻辑封装好,不用重复写。用 def 关键字定义。

1. 基本语法

def 函数名(参数1, 参数2, ...):    """函数文档字符串(说明功能、参数、返回值)"""    函数体(执行逻辑)    return 返回值(可选)

2. 大模型场景示例:计算损失值

大模型训练中每次都要算损失值,封装成函数后直接调用就行:
def calculate_loss(pred, target):    """    计算大模型预测值与真实值的损失(简化版均方误差)    参数:        pred: 模型预测值(浮点数)        target: 真实值(浮点数)    返回:        loss: 损失值    """    loss = (pred - target) ** 2  # 简化的均方误差计算    return loss# 调用函数pred_value = 0.8  # 模型预测的准确率true_value = 0.9  # 真实准确率current_loss = calculate_loss(pred_value, true_value)print(f"当前损失值:{current_loss:.4f}")  # 输出:当前损失值:0.0100
养成习惯:函数一定要写文档字符串(三引号包裹),说明功能、参数、返回值 —— 大模型项目多人协作时,这就是 “代码说明书”!

二、函数参数:灵活传递数据

函数参数有多种类型,能满足大模型开发中不同的配置需求,比如固定参数、默认参数、可变参数。

1. 位置参数:按顺序传递

最基础的参数,调用时必须按定义的顺序传值:

def train_step(model, data, lr):    """单步训练函数(位置参数:模型、数据、学习率)"""    print(f"用学习率{lr}训练模型{model},处理数据{data}")# 调用时顺序不能错!train_step("LLM_Base", "batch_001", 0.001)

2. 默认参数:给参数设默认值

适合大模型中常用的固定配置(比如默认学习率、默认批次大小),调用时可以不传,用默认值:

def train_model(model_name, epochs=100, lr=0.001):    """    大模型训练函数(默认参数:训练轮数、学习率)    参数:        model_name: 模型名称(必填)        epochs: 训练轮数(默认100)        lr: 学习率(默认0.001)    """    print(f"开始训练模型:{model_name}")    print(f"训练轮数:{epochs},学习率:{lr}")# 调用方式1:只传必填参数train_model("LLM_Small")# 调用方式2:覆盖默认参数train_model("LLM_Large", epochs=150, lr=0.0005)

3. 可变参数:传递任意数量数据

适合大模型中批量处理数据(比如传入多个损失值求平均),用 *args 接收任意数量的位置参数:

def avg_loss(*losses):    """计算多轮训练的平均损失(可变参数:任意数量损失值)"""    total = sum(losses)    avg = total / len(losses)    return avg# 调用时可以传任意多个参数print("平均损失:", avg_loss(0.32, 0.28, 0.25, 0.22))  # 输出:0.2675print("平均损失:", avg_loss(0.19, 0.17))  # 输出:0.18

三、函数返回值:输出处理结果

函数可以用 return 返回一个或多个结果,大模型中常用返回值传递训练后的损失值、准确率、模型状态等。

1. 返回单个值

def compute_accuracy(preds, targets):    """计算模型准确率(返回单个值)"""    correct = sum(p == t for p, t in zip(preds, targets))    accuracy = correct / len(preds)    return accuracy# 调用predictions = [1, 0, 1, 1, 0]true_labels = [1, 0, 0, 1, 0]acc = compute_accuracy(predictions, true_labels)print(f"模型准确率:{acc:.2f}")  # 输出:0.80

2. 返回多个值(用元组)

大模型训练常同时返回损失值和准确率,函数可以一次返回多个:

def train_epoch(model, data):    """训练一轮,返回损失值和准确率(返回多个值)"""    # 模拟训练过程    loss = 0.25    accuracy = 0.82    return loss, accuracy  # 用逗号分隔,自动打包成元组# 调用时用多个变量接收epoch_loss, epoch_acc = train_epoch("LLM_Base", "train_data")print(f"本轮损失:{epoch_loss:.2f},准确率:{epoch_acc:.2f}")

四、变量作用域:区分全局与局部

大模型项目中要注意变量的 “作用范围”,避免全局变量和局部变量混淆导致 bug。

1. 局部变量:函数内部定义,仅函数内有效

def train_step():    lr = 0.001  # 局部变量:仅在train_step内有效    print(f"训练步学习率:{lr}")train_step()# print(lr)  # 报错!外部无法访问局部变量

2. 全局变量:函数外部定义,函数内访问需加 global

大模型的全局配置(比如模型名称、最大轮数)常用全局变量:

# 全局变量:函数外部定义MODEL_NAME = "LLM_Global"MAX_EPOCHS = 100def train_model():    global MAX_EPOCHS  # 声明要修改全局变量    MAX_EPOCHS = 150  # 修改全局变量    print(f"训练模型:{MODEL_NAME},最大轮数:{MAX_EPOCHS}")train_model()print(f"修改后的全局最大轮数:{MAX_EPOCHS}")  # 输出:150

五、递归:函数自己调用自己

递归是指函数在内部调用自身的编程方式,适合解决可以分解为相同子问题的场景(比如处理嵌套数据结构、分治算法)。

1. 递归的两个关键要素

  • 终止条件:递归必须有一个明确的结束条件,否则会无限递归导致栈溢出;
  • 递归关系:问题可以分解为规模更小的相同子问题。

2. 大模型场景示例 1 :解析嵌套的模型配置

大模型的配置文件常是嵌套的 JSON 结构,用递归可以方便地遍历所有配置项:

def print_nested_config(config, indent=0):    """    递归打印嵌套的模型配置    参数:        config: 配置字典(可能嵌套)        indent: 缩进层级(用于美观打印)    """    for key, value in config.items():        prefix = "  " * indent        if isinstance(value, dict):            # 如果值是字典,递归处理            print(f"{prefix}{key}:")            print_nested_config(value, indent + 1)        else:            # 否则直接打印            print(f"{prefix}{key}: {value}")# 嵌套的大模型配置llm_nested_config = {    "model": {        "name": "LLM_Recursive",        "architecture": {            "encoder_layers": 12,            "decoder_layers": 12,            "hidden_size": 768        }    },    "training": {        "lr": 0.001,        "batch_size": 32    }}# 调用递归函数打印配置print("===== 嵌套模型配置 =====")print_nested_config(llm_nested_config)
3. 大模型场景示例 2:递归计算学习率衰减(斐波那契式)
def fibonacci_lr(n):    """    递归计算斐波那契式学习率衰减(第n轮的学习率系数)    规律:第1、2轮系数为1,后续每轮为前两轮之和    """    # 终止条件    if n == 1 or n == 2:        return 1.0    # 递归关系    return fibonacci_lr(n-1) + fibonacci_lr(n-2)# 计算前5轮的学习率系数base_lr = 0.001print("===== 斐波那契式学习率衰减 =====")for i in range(1, 6):    coefficient = fibonacci_lr(i)    lr = base_lr / coefficient  # 系数越大,学习率越小    print(f"第{i}轮,学习率系数:{coefficient},学习率:{lr:.6f}")

六、匿名函数(Lambda):一行代码定义简单函数

匿名函数用 lambda 关键字定义,是一种没有函数名、一行代码就能写完的简单函数,适合配合 map()、filter()、sorted() 等函数使用,处理简单的逻辑。

1. 基本语法

Python使用lambda来定义匿名函数,所谓匿名,指其不用def的标准形式定义函数。

lambda参数列表: 表达式

Ølambda 只是一个表达式,函数体比def简单很多。

Ølambda的主体是一个表达式,而不是一个代码块,所以仅仅能在lambda表达式中封装有限的逻辑进去。

Ølambda函数拥有自己的命名空间,且不能访问自己参数列表之外或全局命名空间里的参数。

使用普通函数传参:

def operator(a, b):    return a + b   def function(a, b, operator):    return operator(a, b)print(function(1, 2, operator))

使用匿名函数传参:

deffunction(a, b, operator):   returnoperator(a, b)print(function(1, 2, lambdax, y: x+y))

2. 大模型场景示例 1:配合 map() 批量处理数据

# 模拟大模型的原始预测结果(概率值)raw_predictions = [0.1, 0.5, 0.8, 0.3, 0.9]# 用lambda+map将概率值转为二分类标签(>0.5为1,否则为0)binary_labels = list(map(lambda x: 1 if x > 0.5 else 0, raw_predictions))print("原始预测概率:", raw_predictions)print("二分类标签:", binary_labels)  # 输出:[0, 0, 1, 0, 1]# 用lambda+map对所有预测值进行缩放(乘以100转为百分比)percentage_preds = list(map(lambda x: x * 100, raw_predictions))print("预测概率(百分比):", percentage_preds)
3. 大模型场景示例 2:配合 sorted()排序模型输出

大模型常需要对生成的多个候选结果按置信度排序,lambda 可以方便地指定排序规则:

# 模拟大模型生成的候选回答(包含文本和置信度)candidate_answers = [    {"text": "答案A", "confidence": 0.78},    {"text": "答案B", "confidence": 0.92},    {"text": "答案C", "confidence": 0.85}]# 用lambda指定按置信度从高到低排序sorted_answers = sorted(candidate_answers, key=lambda x: x["confidence"], reverse=True)print("===== 按置信度排序的候选答案 =====")for ans in sorted_answers:    print(f"{ans['text']},置信度:{ans['confidence']:.2f}")

4. 大模型场景示例 3:配合 filter() 筛选有效数据

filter() 可以筛选序列中满足条件的元素,配合 lambda 清洗大模型的训练数据:

# 模拟训练数据(包含文本和长度,需要过滤掉过短的文本)train_data = [    {"text": "你好", "length": 2},    {"text": "这是一个完整的训练样本", "length": 12},    {"text": "Hi", "length": 2},    {"text": "大模型开发需要掌握Python基础", "length": 14}]# 用lambda+filter筛选长度≥5的有效样本valid_data = list(filter(lambda x: x["length"] >= 5, train_data))print(f"原始数据量:{len(train_data)},有效数据量:{len(valid_data)}")print("有效样本:")for data in valid_data:    print(f"  {data['text']}")
五、实战案例
案例1、大模型训练函数封装
"""实战案例:大模型简化训练流程封装功能:1. 数据预处理函数2. 单步训练函数3. 完整训练函数(整合流程)"""# 全局配置MODEL_CONFIG = {    "model_name": "LLM_Practice",    "lr": 0.001,    "batch_size": 32}def preprocess_data(raw_data):    """数据预处理:清洗并格式化数据"""    processed = [d.strip().lower() for d in raw_data]    return processeddef train_one_batch(model, batch_data, lr):    """单批次训练:返回损失值"""    # 模拟训练    loss = 0.3 - (lr * 10)    return lossdef full_train(model_config, raw_data, epochs=5):    """    完整训练流程    参数:        model_config: 模型配置字典        raw_data: 原始训练数据        epochs: 训练轮数    返回:        loss_history: 每轮损失值列表    """    # 1. 数据预处理    data = preprocess_data(raw_data)    print(f"预处理完成,数据量:{len(data)}")    # 2. 训练循环    loss_history = []    for epoch in range(epochs):        loss = train_one_batch(model_config["model_name"], data, model_config["lr"])        loss_history.append(loss)        print(f"第{epoch+1}轮,损失值:{loss:.4f}")    return loss_history# 调用完整训练函数raw_train_data = ["  Hello LLM  ", "  Python Dev  ", "  Model Train  "]history = full_train(MODEL_CONFIG, raw_train_data, epochs=3)print(f"\n训练完成,损失历史:{history}")

运行结果:

预处理完成,数据量:3第1轮,损失值:0.2900第2轮,损失值:0.2900第3轮,损失值:0.2900训练完成,损失历史:[0.29, 0.29, 0.29]
案例2、整合递归与 Lambda
"""补充实战:整合递归与Lambda处理大模型数据"""# 1. 递归解析嵌套配置def parse_config(config, parent_key=""):    """递归展平嵌套配置字典"""    items = []    for k, v in config.items():        new_key = f"{parent_key}.{k}" if parent_key else k        if isinstance(v, dict):            items.extend(parse_config(v, new_key))        else:            items.append((new_key, v))    return itemsnested_config = {    "model": {"name": "LLM_Lambda", "size": "base"},    "train": {"lr": 0.001, "epochs": 100}}flat_config = dict(parse_config(nested_config))print("展平后的配置:", flat_config)# 2. 用Lambda处理配置值# 将所有数值型配置值转为字符串processed_config = {k: (lambda v: str(v) if isinstance(v, (int, float)) else v)(v)                    for k, v in flat_config.items()}print("处理后的配置:", processed_config)
运行结果:
展平后的配置: {'model.name': 'LLM_Lambda', 'model.size': 'base', 'train.lr': 0.001, 'train.epochs': 100}处理后的配置: {'model.name': 'LLM_Lambda', 'model.size': 'base', 'train.lr': '0.001', 'train.epochs': '100'}

下一篇预告

今天我们完整掌握了 Python 函数的全知识点,从基础的定义调用、参数返回值,到进阶的递归、匿名函数,再到工程化的逻辑封装,能把大模型开发中的复杂逻辑拆解为可复用的函数模块。下一篇我们将进入第 7 章 文件操作:学习如何用 Python 读取训练数据集、保存模型权重、写入训练日志、处理大模型常用的 txt、json、csv 等格式文件

如果在函数使用中遇到问题,评论区贴出你的代码和报错信息, 觉得干货有用,别忘了点赞 + 在看 + 转发,让更多想入门大模型的朋友一起学习!

最新文章

随机文章