60分钟吃掉FM算法

Python排序算法动画可视化教学工具 排序算法是数据结构与算法课程的核心基础概念,其执行过程具有强状态演化特性,传统伪代码难以呈现动态逻辑流。基于生成器(yield)与matplotlib.animation.FuncAnimation的可视化实现,可将冒泡、归并、快排等算法每一步比较、交换、递归分割等操作实时映射为条形图高度变化与颜色状态流转,既符合算法‘逐步生成有序序列’的本质原理,又显著提升初学者的直觉理解效率。该方案技术门槛低、可调试性强,适用于编程入门、课堂教学演示及面试复习等典型工程教育场景,是Python可视化与算法教学深度融合的 阅读详情

FM算法全称为因子分解机 (FactorizationMachine)。

它是广告和推荐领域非常著名的算法,在线性回归模型上考虑了特征的二阶交互。

适合捕捉大规模稀疏特征(类别特征)当中的特征交互。

FM及其衍生的一些较有名的算法的简要介绍如下:

  • FM(FactorizationMachine):在LR基础上用隐向量点积实现自动化特征二阶交叉,且交互项的计算复杂度是O(n),效果显著好于LR,速度极快接近LR。

  • FFM(Field Aware FM): 在FM的基础上考虑对不同的特征域(Field,可以理解成特征的分组)使用不同的隐向量。效果好于FM,但参数量急剧增加,且预测性能急剧下降。

  • Bilinear-FFM: 双线性FFM。为了减少FFM的参数量,设计共享矩阵来代替针对不同Field的多个隐向量。效果接近FFM,但参数量大大减少,与FM相当。交互后添加LayerNormalization时效果略好于FFM.

  • DeepFM: 使用FM模型代替DeepWide中的Wide部分,且FM部分的隐向量与Deep部分的Embedding向量是共享的。FM部分可以捕获二阶显式特征交叉,而Deep部分能够捕获高阶隐式特征组合和交叉。

  • FiBiNET: 使用SE注意力(Squeeze-and-Excitation)机制来捕获特征重要性,并且使用Bilinear-FFM来捕获二阶特征交互。

参考文章:张俊林《FFM及DeepFFM模型在推荐系统的探索》https://zhuanlan.zhihu.com/p/67795161

公众号后台回复关键词:FM,获取本文全部源代码和数据集。

一,FM原理解析

FM模型的表达形式如下:

其中 前两项与 线性回归一致。

第三项为特征交互项。用隐向量的点积来计算交互项的系数。这样做比直接设定一个的交互参数矩阵的好处是减少了参数数量,参数数量从 减少为 ,其中k为隐向量的长度。

从数学上,FM算法用一组向量的两两内积代替了交互参数矩阵,等价于将对称矩阵W分解成如下形式,这也是为什么FM算法被叫做因子分解机。

非常有意思的是,交互项的计算复杂度也可以由 降低为 ,这样FM前向推断的计算复杂度近似为线性复杂度。对于特征数量n非常大而稀疏的模型,计算起来毫无压力。

交互项的简化计算类似于

402 Payment Required

402 Payment Required

402 Payment Required

可以看到交互项的计算复杂度已经变成 了

因此 FM的模型形式也可以改写成:

402 Payment Required

注意到

402 Payment Required

可见,只要训练样本中存在不等于0的 ,就能够给隐向量贡献梯度,从而学到有效的表示。

同理,只要训练样本中存在不等于0的 ,就能够给隐向量贡献梯度,从而学到有效的表示。

然后,就可以计算出有意义的交互项的权重。

这非常重要,这说明非零的交互项权重可以在训练样本中不存在 和同时不为0的样本的发生。

这是FM面对稀疏特征具有很强泛化性的原因。

考虑一个典型的给用户推荐商品的推荐场景中,用户所在城市特征和商品类目特征的交互。

葫芦岛是一个小城市,渔网是一种小众商品。它们都是稀疏特征,绝大部分样本在这两个onehot位上的取值都是0.

稀疏乘以稀疏更加稀疏,所以在训练样本中可能根本不存在葫芦岛城市的用户购买渔网这样的样本。

但是只要训练样本中存在着葫芦岛的用户购买其它商品这样的样本,也存在其他城市用户购买渔网这样的样本,FM模型就可以给葫芦岛市的用户购买渔网的可能性作出一个估计,这个值可能不小,最后甚至会给葫芦岛的用户推荐渔网。

这就是FM面对稀疏特征具有很强泛化性的一个例子。

二,手工代码实现

下面是FM模型的一个完整pytorch实现。

402 Payment Required

注意的是,我们代码中的embedding向量或者线性层作用结果实际上是 的结果。这是许多读者包括我在学习FM时候感到困惑的一个地方。

对于 离散特征,onehot编码后其 总是等于1或者0,不为0的那些项才会保留到结果中,此时总是等于1,因此就等于其embedding向量。对于连续特征,通过一个不带偏置的Linear层作用,获取到的实际上就是 ,包含了因子。

import torch 
from torch import nn
from torch import nn,Tensor 
import torch.nn.functional as F 

class NumEmbedding(nn.Module):
    """
    连续特征用linear层编码
    输入shape: [batch_size,features_num(n), d_in], # d_in 通常是1
    输出shape: [batch_size,features_num(n), d_out]
    """
    
    def __init__(self, n: int, d_in: int, d_out: int, bias: bool = False) -> None:
        super().__init__()
        self.weight = nn.Parameter(Tensor(n, d_in, d_out))
        self.bias = nn.Parameter(Tensor(n, d_out)) if bias else None
        with torch.no_grad():
            for i in range(n):
                layer = nn.Linear(d_in, d_out)
                self.weight[i] = layer.weight.T
                if self.bias is not None:
                    self.bias[i] = layer.bias

    def forward(self, x_num):
        # x_num: batch_size, features_num, d_in
        assert x_num.ndim == 3
        #x = x_num[..., None] * self.weight[None]
        #x = x.sum(-2)
        x = torch.einsum("bfi,fij->bfj",x_num,self.weight)
        if self.bias is not None:
            x = x + self.bias[None]
        return x
    
class CatEmbedding(nn.Module):
    """
    离散特征用Embedding层编码
    输入shape: [batch_size,features_num], 
    输出shape: [batch_size,features_num, d_embed]
    """
    def __init__(self, categories, d_embed):
        super().__init__()
        self.embedding = torch.nn.Embedding(sum(categories), d_embed)
        self.offsets = nn.Parameter(
                torch.tensor([0] + categories[:-1]).cumsum(0),requires_grad=False)
        
        torch.nn.init.xavier_uniform_(self.embedding.weight.data)

    def forward(self, x_cat):
        """
        :param x_cat: Long tensor of size ``(batch_size, features_num)``
        """
        x = x_cat + self.offsets[None]
        return self.embedding(x) 
    
class CatLinear(nn.Module):
    """
    离散特征用Embedding实现线性层(等价于先F.onehot再nn.Linear())
    输入shape: [batch_size,features_num], 
    输出shape: [batch_size,features_num, d_out]
    """
    def __init__(self, categories, d_out=1):
        super().__init__()
        self.fc = nn.Embedding(sum(categories), d_out)
        self.bias = nn.Parameter(torch.zeros((d_out,)))
        self.offsets = nn.Parameter(
                torch.tensor([0] + categories[:-1]).cumsum(0),requires_grad=False)

    def forward(self, x_cat):
        """
        :param x: Long tensor of size ``(batch_size, features_num)``
        """
        x = x_cat + self.offsets[None]
        return torch.sum(self.fc(x), dim=1) + self.bias 
    
    
class FMLayer(nn.Module):
    """
    FM交互项
    """

    def __init__(self, reduce_sum=True):
        super().__init__()
        self.reduce_sum = reduce_sum

    def forward(self, x): #注意:这里的x是公式中的 <v_i> * xi
        """
        :param x: Float tensor of size ``(batch_size, num_features, k)``
        """
        square_of_sum = torch.sum(x, dim=1) ** 2
        sum_of_square = torch.sum(x ** 2, dim=1)
        ix = square_of_sum - sum_of_square
        if self.reduce_sum:
            ix = torch.sum(ix, dim=1, keepdim=True)
        return 0.5 * ix
    
class FM(nn.Module):
    """
    完整FM模型。
    """

    def __init__(self, d_numerical, categories=None, d_embed=4,
                 n_classes = 1):
        super().__init__()
        if d_numerical is None:
            d_numerical = 0
        if categories is None:
            categories = []
        self.categories = categories
        self.n_classes = n_classes
        
        self.num_linear = nn.Linear(d_numerical,n_classes) if d_numerical else None
        self.cat_linear = CatLinear(categories,n_classes) if categories else None
        
        self.num_embedding = NumEmbedding(d_numerical,1,d_embed) if d_numerical else None
        self.cat_embedding = CatEmbedding(categories, d_embed) if categories else None
        
        if n_classes==1:
            self.fm = FMLayer(reduce_sum=True)
            self.fm_linear = None
        else:
            assert n_classes>=2
            self.fm = FMLayer(reduce_sum=False)
            self.fm_linear = nn.Linear(d_embed,n_classes)

    def forward(self, x):
        
        """
        x_num: numerical features
        x_cat: category features
        """
        x_num,x_cat = x
        
        #linear部分
        x = 0.0
        if self.num_linear:
            x = x + self.num_linear(x_num) 
        if self.cat_linear:
            x = x + self.cat_linear(x_cat)
        
        #交叉项部分
        x_embedding = []
        if self.num_embedding:
            x_embedding.append(self.num_embedding(x_num[...,None]))
        if self.cat_embedding:
            x_embedding.append(self.cat_embedding(x_cat))
        x_embedding = torch.cat(x_embedding,dim=1)
        
        if self.n_classes==1:
            x = x + self.fm(x_embedding)
            x = x.squeeze(-1)
        else: 
            x = x + self.fm_linear(self.fm(x_embedding)) 
        return x
##测试 NumEmbedding

num_embedding = NumEmbedding(2,1,4)
x_num = torch.randn(2,2)
x_out = (num_embedding(x_num.unsqueeze(-1)))
print(x_out.shape)
##测试 CatEmbedding

cat_embedding = CatEmbedding(categories = [3,2,2],d_embed=4) 
x_cat = torch.randint(0,2,(2,3))
x_out = cat_embedding(x_cat)
print(x_cat.shape)
print(x_out.shape)
##测试 CatLinear

cat_linear = CatLinear(categories = [3,2,2],d_out=1) 
x_cat = torch.randint(0,2,(2,3))
x_out = cat_linear(x_cat)
print(x_cat.shape)
print(x_out.shape)
##测试 FMLayer

fm_layer = FMLayer(reduce_sum=False)

x = torch.randn(2,3,4)
x_out = fm_layer(x)
print(x_out.shape)
##测试 FM

fm = FM(d_numerical = 3, categories = [4,3,2],
        d_embed = 4,n_classes = 2)
self = fm 
x_num = torch.randn(2,3)
x_cat = torch.randint(0,2,(2,3))
fm((x_num,x_cat))

三,Cretio数据集完整范例

Cretio数据集是一个经典的广告点击率CTR预测数据集。

这个数据集的目标是通过用户特征和广告特征来预测某条广告是否会为用户点击。

数据集有13维数值特征(I1~I13)和26维类别特征(C14~C39), 共39维特征, 特征中包含着许多缺失值。

训练集4000万个样本,测试集600万个样本。数据集大小超过100G.

此处使用的是采样100万个样本后的cretio_small数据集。

#!pip install -U torchkeras -i https://pypi.org/simple/
import numpy as np 
import pandas as pd 
import datetime 

from sklearn.model_selection import train_test_split 

import torch 
from torch import nn 
from torch.utils.data import Dataset,DataLoader  
import torch.nn.functional as F 
import torchkeras 

def printlog(info):
    nowtime = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
    print("\n"+"=========="*8 + "%s"%nowtime)
    print(info+'...\n\n')

1,准备数据

from sklearn.preprocessing import LabelEncoder,QuantileTransformer
from sklearn.pipeline import Pipeline 
from sklearn.impute import SimpleImputer 

dfdata = pd.read_csv("../data/criteo_small.zip",sep="\t",header=None)
dfdata.columns = ["label"] + ["I"+str(x) for x in range(1,14)] + [
    "C"+str(x) for x in range(14,40)]

cat_cols = [x for x in dfdata.columns if x.startswith('C')]
num_cols = [x for x in dfdata.columns if x.startswith('I')]
num_pipe = Pipeline(steps = [('impute',SimpleImputer()),('quantile',QuantileTransformer())])

for col in cat_cols:
    dfdata[col]  = LabelEncoder().fit_transform(dfdata[col])

dfdata[num_cols] = num_pipe.fit_transform(dfdata[num_cols])

categories = [dfdata[col].max()+1 for col in cat_cols]
dfdata

157203f038398fd2352efd37440cff8b.png

import torch 
from torch.utils.data import Dataset,DataLoader 

#DataFrame转换成torch数据集Dataset, 特征分割成X_num,X_cat方式
class DfDataset(Dataset):
    def __init__(self,df,
                 label_col,
                 num_features,
                 cat_features,
                 categories,
                 is_training=True):
        
        self.X_num = torch.tensor(df[num_features].values).float() if num_features else None
        self.X_cat = torch.tensor(df[cat_features].values).long() if cat_features else None
        self.Y = torch.tensor(df[label_col].values).float() 
        self.categories = categories
        self.is_training = is_training
    
    def __len__(self):
        return len(self.Y)
    
    def __getitem__(self,index):
        if self.is_training:
            return ((self.X_num[index],self.X_cat[index]),self.Y[index])
        else:
            return (self.X_num[index],self.X_cat[index])
    
    def get_categories(self):
        return self.categories
dftrain_val,dftest = train_test_split(dfdata,test_size=0.2)
dftrain,dfval = train_test_split(dftrain_val,test_size=0.2)

ds_train = DfDataset(dftrain,label_col = "label",num_features = num_cols,cat_features = cat_cols,
                    categories = categories, is_training=True)

ds_val = DfDataset(dfval,label_col = "label",num_features = num_cols,cat_features = cat_cols,
                    categories = categories, is_training=True)

ds_test = DfDataset(dftest,label_col = "label",num_features = num_cols,cat_features = cat_cols,
                    categories = categories, is_training=True)
dl_train = DataLoader(ds_train,batch_size = 2048,shuffle=True)
dl_val = DataLoader(ds_val,batch_size = 2048,shuffle=False)
dl_test = DataLoader(ds_test,batch_size = 2048,shuffle=False)

for features,labels in dl_train:
    break

2,定义模型

def create_net():
    net = FM(
        d_numerical= ds_train.X_num.shape[1],
        categories= ds_train.get_categories(),
        d_embed = 8, 
        n_classes = 1
    )
    return net 

from torchkeras import summary

net = create_net()
summary(net,input_data=features);

10f587b6fbd792a05e74e91ea0d11623.png

3,训练模型

此处使用的训练代码是一套通用代码,仿照keras风格构建pytorch模型的训练循环,来自我写的torchkeras库中的KerasModel类的源码。总共不到200行代码,包括进度条、EarlyStopping、GPU支持等功能,非常简洁实用,有兴趣的同学可以去github上搜索torchkeras参考使用。

import os,sys,time
import numpy as np
import pandas as pd
import datetime 
from tqdm import tqdm 

import torch
from torch import nn 
from accelerate import Accelerator
from copy import deepcopy


def printlog(info):
    nowtime = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
    print("\n"+"=========="*8 + "%s"%nowtime)
    print(str(info)+"\n")
    
class StepRunner:
    def __init__(self, net, loss_fn,stage = "train", metrics_dict = None, 
                 optimizer = None, lr_scheduler = None,
                 accelerator = None
                 ):
        self.net,self.loss_fn,self.metrics_dict,self.stage = net,loss_fn,metrics_dict,stage
        self.optimizer,self.lr_scheduler = optimizer,lr_scheduler
        self.accelerator = accelerator
    
    def __call__(self, features, labels):
        #loss
        preds = self.net(features)
        loss = self.loss_fn(preds,labels)

        #backward()
        if self.optimizer is not None and self.stage=="train":
            if self.accelerator is  None:
                loss.backward()
            else:
                self.accelerator.backward(loss)
            self.optimizer.step()
            if self.lr_scheduler is not None:
                self.lr_scheduler.step()
            self.optimizer.zero_grad()
            
        #metrics
        step_metrics = {self.stage+"_"+name:metric_fn(preds, labels).item() 
                        for name,metric_fn in self.metrics_dict.items()}
        return loss.item(),step_metrics
    
    
class EpochRunner:
    def __init__(self,steprunner):
        self.steprunner = steprunner
        self.stage = steprunner.stage
        self.steprunner.net.train() if self.stage=="train" else self.steprunner.net.eval()
        
    def __call__(self,dataloader):
        total_loss,step = 0,0
        loop = tqdm(enumerate(dataloader), total =len(dataloader))
        for i, batch in loop:
            features,labels = batch
            loss, step_metrics = self.steprunner(features,labels)

            step_log = dict({self.stage+"_loss":loss},**step_metrics)

            total_loss += loss
            step+=1
            if i!=len(dataloader)-1:
                loop.set_postfix(**step_log)
            else:
                epoch_loss = total_loss/step
                epoch_metrics = {self.stage+"_"+name:metric_fn.compute().item() 
                                 for name,metric_fn in self.steprunner.metrics_dict.items()}
                epoch_log = dict({self.stage+"_loss":epoch_loss},**epoch_metrics)
                loop.set_postfix(**epoch_log)

                for name,metric_fn in self.steprunner.metrics_dict.items():
                    metric_fn.reset()
        return epoch_log

class KerasModel(torch.nn.Module):
    def __init__(self,net,loss_fn,metrics_dict=None,optimizer=None,lr_scheduler = None):
        super().__init__()
        self.accelerator = Accelerator()
        self.history = {}
        
        self.net = net
        self.loss_fn = loss_fn
        self.metrics_dict = nn.ModuleDict(metrics_dict) 
        
        self.optimizer = optimizer if optimizer is not None else torch.optim.Adam(
            self.parameters(), lr=1e-2)
        self.lr_scheduler = lr_scheduler
        
        self.net,self.loss_fn,self.metrics_dict,self.optimizer = self.accelerator.prepare(
            self.net,self.loss_fn,self.metrics_dict,self.optimizer)

    def forward(self, x):
        if self.net:
            return self.net.forward(x)
        else:
            raise NotImplementedError


    def fit(self, train_data, val_data=None, epochs=10, ckpt_path='checkpoint.pt', 
            patience=5, monitor="val_loss", mode="min"):
        
        train_data = self.accelerator.prepare(train_data)
        val_data = self.accelerator.prepare(val_data) if val_data else []

        for epoch in range(1, epochs+1):
            printlog("Epoch {0} / {1}".format(epoch, epochs))
            
            # 1,train -------------------------------------------------  
            train_step_runner = StepRunner(net = self.net,stage="train",
                    loss_fn = self.loss_fn,metrics_dict=deepcopy(self.metrics_dict),
                    optimizer = self.optimizer, lr_scheduler = self.lr_scheduler,
                    accelerator = self.accelerator)
            train_epoch_runner = EpochRunner(train_step_runner)
            train_metrics = train_epoch_runner(train_data)
            
            for name, metric in train_metrics.items():
                self.history[name] = self.history.get(name, []) + [metric]

            # 2,validate -------------------------------------------------
            if val_data:
                val_step_runner = StepRunner(net = self.net,stage="val",
                    loss_fn = self.loss_fn,metrics_dict=deepcopy(self.metrics_dict),
                    accelerator = self.accelerator)
                val_epoch_runner = EpochRunner(val_step_runner)
                with torch.no_grad():
                    val_metrics = val_epoch_runner(val_data)
                val_metrics["epoch"] = epoch
                for name, metric in val_metrics.items():
                    self.history[name] = self.history.get(name, []) + [metric]
            
            # 3,early-stopping -------------------------------------------------
            arr_scores = self.history[monitor]
            best_score_idx = np.argmax(arr_scores) if mode=="max" else np.argmin(arr_scores)
            if best_score_idx==len(arr_scores)-1:
                torch.save(self.net.state_dict(),ckpt_path)
                print("<<<<<< reach best {0} : {1} >>>>>>".format(monitor,
                     arr_scores[best_score_idx]),file=sys.stderr)
            if len(arr_scores)-best_score_idx>patience:
                print("<<<<<< {} without improvement in {} epoch, early stopping >>>>>>".format(
                    monitor,patience),file=sys.stderr)
                self.net.load_state_dict(torch.load(ckpt_path))
                break 
            
        return pd.DataFrame(self.history)

    @torch.no_grad()
    def evaluate(self, val_data):
        val_data = self.accelerator.prepare(val_data)
        val_step_runner = StepRunner(net = self.net,stage="val",
                    loss_fn = self.loss_fn,metrics_dict=deepcopy(self.metrics_dict),
                    accelerator = self.accelerator)
        val_epoch_runner = EpochRunner(val_step_runner)
        val_metrics = val_epoch_runner(val_data)
        return val_metrics
        
       
    @torch.no_grad()
    def predict(self, dataloader):
        dataloader = self.accelerator.prepare(dataloader)
        result = torch.cat([self.forward(t[0]) for t in dataloader])
        return result.data
from torchkeras.metrics import AUC

loss_fn = nn.BCEWithLogitsLoss()

metrics_dict = {"auc":AUC()}

optimizer = torch.optim.Adam(net.parameters(), lr=0.005, weight_decay=0.001) 

model = KerasModel(net,
                   loss_fn = loss_fn,
                   metrics_dict= metrics_dict,
                   optimizer = optimizer
                  )
dfhistory = model.fit(train_data=dl_train,val_data=dl_val,epochs=30, patience=5,
                      monitor = "val_auc",mode="max")

572eda42617f0815d34d0013a583e4a0.png

可以看到,未经过调参,我们的FM模型在验证集的AUC指标为0.772,not bad!

4,评估模型

%matplotlib inline
%config InlineBackend.figure_format = 'svg'

import matplotlib.pyplot as plt

def plot_metric(dfhistory, metric):
    train_metrics = dfhistory["train_"+metric]
    val_metrics = dfhistory['val_'+metric]
    epochs = range(1, len(train_metrics) + 1)
    plt.plot(epochs, train_metrics, 'bo--')
    plt.plot(epochs, val_metrics, 'ro-')
    plt.title('Training and validation '+ metric)
    plt.xlabel("Epochs")
    plt.ylabel(metric)
    plt.legend(["train_"+metric, 'val_'+metric])
    plt.show()
plot_metric(dfhistory,"loss")

104a02aaba5b4e40b927d42463d06722.png

plot_metric(dfhistory,"auc")

15f97eb729ab45da0878df8aeb36b0e3.png

model.evaluate(dl_train)

{'val_loss': 0.4663983137843708, 'val_auc': 0.7798623442649841}

model.evaluate(dl_val)

{'val_loss': 0.4729234987421881, 'val_auc': 0.7715966105461121}

5,使用模型

from sklearn.metrics import roc_auc_score
preds = F.sigmoid(model.predict(dl_val))
labels = torch.cat([x[-1] for x in dl_val])

val_auc = roc_auc_score(labels.numpy(),preds.numpy())
print(val_auc)

0.7715966341541106

6,保存模型

模型最佳权重已经保存在 model.fit(ckpt_path) 传入的参数中了。

net_clone = create_net()
net_clone.load_state_dict(torch.load("checkpoint.pt"))
from sklearn.metrics import roc_auc_score
preds = torch.cat([F.sigmoid(net_clone(x[0])).data for x in dl_val]) 
labels = torch.cat([x[-1] for x in dl_val])

val_auc = roc_auc_score(labels.numpy(),preds.numpy())
print(val_auc)

0.7715966341541106

公众号后台回复关键词:FM,获取本文全部源代码和数据集。

万水千山总是情,点个在看行不行?😋 

以上。

1451e8ef2a64cdb490750b91889e5729.png

深度学习算法选型速查表:按数据维度与工程约束决策 深度学习算法本质是解决特定数据结构问题的工具,其核心不在模型架构本身,而在匹配‘数据如何携带信息’——空间主导型(如图像)依赖局部不变性,时序主导型(如传感器流)需建模长程依赖,关系主导型(如知识图谱)要求非欧结构感知,多模态耦合型则强调跨模态语义对齐。理解这一原理,才能避开用CNN处理时序、用LSTM建模图结构等典型工程陷阱。技术价值体现在落地可行性:显存占用、推理延迟、小样本鲁棒性、硬件亲和度等硬指标直接决定模型能否上线。在工业质检、金融风控、医疗影像、智能物流等真实场景中,算法选型必须基于数据主导维度 阅读详情

相关推荐

STM32H725 550MHz实战:时钟树、封装与内存协同设计指南

在嵌入式系统中,MCU主频提升并非简单叠加性能,而是涉及时钟树架构、物理封装信号完整性、紧耦合内存(TCM)与AXI总线协同等底层机制。550MHz Cortex-M7内核的真正价值在于全链路时序精度重构,其性能释放高度依赖PLL多域分频、DTCM/ITCM Bank优先级配置及ZGT6封装的电气隔离设计。这类高主频MCU广泛应用于电机控制、边缘AI推理、光模块标定等对纳秒级时序敏感的场景。本文深入解析STM32H725在时钟树配置、PCB布局约束、TCM访问仲裁及外设边界调优中的关键技术要点,帮助工程师跨

weixin_33922670的博客 401

Wide&Deep Model、Wide Model(LR)、Deep Model、DeepFm Model、NFM Model复现笔记

声明:本模型复现笔记记录自己学习过程,如果有错误请各位老师批评指正。 本周复现了Wide&Deep Model、Wide Model、Deep Model、DeepFm Model、NFM Model dataset:cretio数据集(选取了train 20000, test 5000) Wide&Deep Model结合了Wide Model(LR)的记忆性和Deep Model的泛化能力,对于部署应用来说会提高用户的获取率和满意度,但是Wide&Deep的Wide part,需

aaHua_ 1805

梯度下降变体实战指南:从SGD到Adam的工程选型逻辑

梯度下降是机器学习模型训练的核心优化机制,其本质是通过迭代更新参数以最小化损失函数。不同变体如SGD、Momentum、Adam等,分别在梯度估计精度、收敛速度与数值稳定性之间做出权衡。技术价值在于适配真实工程约束:数据规模决定采样策略(全量/小批量/单样本),硬件资源影响计算效率,模型结构复杂度则关联优化器对梯度噪声与尺度差异的鲁棒性。典型应用场景包括线性回归拟合、推荐系统排序、图像分类微调等,其中Mini-batch SGD与Adam已成为工业界默认选择。本文聚焦Gradient Descent和Var

weixin_34167819的博客 341

【推荐系统】Criteo数据集介绍

最近在学习一个ctr预估的开源项目,大部分都使用的是Criteo数据集,是非常经典的点击率预估比赛。 数据下载地址:https://www.kaggle.com/c/criteo-display-ad-challenge/data 进行个简单的背景介绍,方便自己之后回顾。 英文原版,哈哈哈哈 File descriptions train.csv- The training set consists of a portion of Criteo's traffic over a period .

littlemichelle 1万+

Criteo数据集探索

Data fields Label - Target variable that indicates if an ad was clicked (1) or not (0).(待预测广告,被点击是1,没有被点击是0。) I1-I13 - A total of 13 columns of integer features (mostly count features).(总共 13 列数值型特征(主要是计数特征)。) C1-C26 - A total of 26 columns of categorical

具身机器人和通用AI 1325

kaggle比赛criiteo经典CTR预估数据集(小型)

kaggle比赛criiteo经典CTR预估数据集(小型)

【推荐实践】腾讯推荐系统中的深度匹配模型

省时查报告-专业、及时、全面的行研报告库省时查方案-专业、及时、全面的营销策划方案库【免费下载】2022年6月热门报告合集从零开始了解推荐系统全貌机器学习在B站推荐系统中的应用实践微信视频号实时推荐技术架构分享小红书推荐中台实践快手推荐系统精排模型实践导读:推荐系统和搜索应该是机器学习乃至深度学习在工业界落地应用最多也最容易变现的场景。而无论是搜索还是推荐,本质其实都是匹...

m0_37586850的博客 3601

criteo dataset(CTR数据集)part1

Display Advertising Challenge Predict click-through rates on display ads

【推荐算法】DeepFM模型:A Factorization-Machine based Neural Network for CTR Prediction

DeepFM模型是由哈尔滨工业大学和华为实验室联合提出的,将FM模型结构与Wide&Deep模型进行了融合。DeepFM可以同时提取低阶组合特征与高阶组合特征。其中,FM模型负责提取一阶特征以及两两交叉特征;DNN模型负责提取高阶特征。相比于谷歌最新的Wide&Deep模型,DeepFM模型的Deep component和FM component从Embedding层共享数据输入,同时不需要专门的特征工程,在推荐系统中取得了不错的推荐效果。

长相忆兮长相忆的专栏 4289

如何使用ArcGIS Pro制作带基底三维地图

点击运行生成范围线,因为之前对高程进行了夸大,导致生成的范围线和地形边缘不重合,我们打开范围线的图层属性,选择高程选项卡,要素位于选择地面上,如下图所示。目前制作的三维地图下面是空的一片,现在添加一个基底,在工具箱内点击“3D Analyst工具\栅格\转换\栅格范围”,调用栅格范围工具,如下图所示。打开ArcGIS Pro,新建一个局部场景,在高程表面下,地面上点击右键,选择添加高程源图层,将需要制作三维地图的DEM数据加载进来,如下图所示。在要素图层菜单内,类型选择绝对高度,如下图所示。

3977

代码实现 —— 基于 STM32 的可见光通信系统课程设计

基于STM32F103ZET6,源码如需移植,需要修改定时器捕获通道引脚,及定时器,如果你也有这个课设任务,希望对你有所帮助。

不善挽留 1万+

60分钟吃掉嘎嘣脆的DeepCross模型

谷歌在CTR预估和推荐排序模型方面有3篇相对重要的文章。第1篇是2016年的Deep&Wide,第2篇是2017年的Deep&Cross(DCN),第3篇是2020年的DCN-V2.这3篇文章的核心思想分别用1句话概括如下:第1篇Deep&Wide说,线性回归LR具有好的记忆能力(Wide部分),多层感知机DNN具有好的泛化能力(Deep部分),把...

Python_Ai_Road的博客 2057

华为硬件逻辑岗笔试题(一)

积少成多,集腋成裘,坚持!!! 目录 1. 进制转换 2. 状态机和编码方式 3. 存储器的分类 4. Verilog语法中的操作符 5. 对组合逻辑的认识 6. 对时序逻辑的认识 7. 竞争冒险的认识 8. 基本时序逻辑电路 9. 建立时间和保持时间 10. 同步时序电路 11. 组合逻辑和时序逻辑判断 13. 基本总线的理解 14.加法器 15.FPGA开发工具 1. 进制转换 1、十进制46.25对应的二进制表达式为( )。 A 101110.11...

qq_42235129的博客 1万+

60分钟吃掉三杀模型FiBiNET

神经网络的结构设计有3个主流的高级技巧:1,高低融合 (将高层次特征与低层次特征融合,提升特征维度的丰富性和多样性,像人一样同时考虑整体和细节)2,权值共享 (一个权值矩阵参与多个不同的计算,降低参数规模并同时缓解样本稀疏性,像人一样一条知识多处运用)3,动态适应 (不同的输入样本使用不同的权值矩阵,动态地进行特征选择并赋予特征重要度解释性,像人一样聚焦重要信息排除干扰信...

Python_Ai_Road的博客 637

TMC步进电机驱动stealthChop

经过九九八十一难,芯片手册拜读了好多遍,找了好多资料,问了好多人使用TMC2660驱动步进电机终于成功了。最后的问题居然是硬件把管脚画错了,然后我又没有检查,哭。。。

那可真是太开心了的博客 4489

pip——【Fatal error in launcher: Unable to create process】的深度排查与修复指南

本文深度解析了Python包管理工具pip报错【Fatal error in launcher: Unable to create process】的根本原因与解决方案。该错误通常由Python解释器路径变更、虚拟环境损坏或多版本冲突导致。文章提供了从快速排查到彻底修复的完整指南,包括使用`python -m pip`命令绕过启动器、修复或重装pip、重建虚拟环境等核心方法,并给出了预防此错误的最佳实践。

weixin_29306261的博客 598

GNU Radio+PlutoSDR构建可调试FM收音机实战指南

软件定义无线电(SDR)是现代射频系统开发与教学的核心技术,其本质是将传统硬件功能通过数字信号处理实现可编程化。GNU Radio作为开源信号流图框架,配合PlutoSDR高性能射频前端,构成从电磁波接收、下变频、解调到音频输出的完整可观察链路。该组合支持实时频谱分析、参数动态调节与模块级故障定位,显著优于RTL-SDR等入门设备在IQ精度、相位噪声和带宽稳定性方面的局限。广泛应用于通信原理验证、嵌入式射频测试、无线电监测及创客项目开发。本文以FM广播接收为切入点,详解GNU Radio流图设计逻辑、Plu

weixin_30595035的博客 362

SAP FICO 内部往来对账功能开发说明书(包括测试样例、程序代码仅作参考,不保证一定可以运行)

SAP FICO 内部往来对账功能开发说明书(包括开发源代码、测试样例、FS)

我好像病了的博客 1222

算法做题打卡

csdn算法技能树,基础1-5。通过算法提升解题思想,同时使用golang语言,有利于加强和巩固golang基础

jayLog的博客 364

36、基于启发式的双向RRT*路径规划算法解析

本文介绍了一种基于启发式的双向RRT*路径规划算法(LGHB-RRT*),通过地图预处理、通道区域提取和通道识别点定义,结合随机树的引导生长与可变密度采样机制,显著提升了在复杂通道环境下的搜索效率与成功率。算法采用双向扩展结构,并引入启发式生长策略引导树向通道关键点发展,同时利用路径优化简化最终路径。仿真结果表明,该算法在多种复杂地图中均能高效找到最优路径,优于传统RRT*和Bi-RRT*算法,具备良好的适应性与应用前景。

rgv234567的博客 116

泰凌微8258入门教程 基础篇①——Bluetooth® SIG Mesh 快速上手

Bluetooth® SIG Mesh Quick Start

6729

[考试反思]0904NOIP模拟测试37:守望

100分并列的还有4个没粘 总分是大脸的一半,然而还只低了2名。差距好大。。。但其实后面的分数段又很密集,和我都差不了多少。。。 我可能也是最水的那一个,排行榜前7个里面就我没有AC。全是暴力。。。 这次考试的时间分配有点问题,要记录一下。 上来过了一边题目,T2的70分很好拿但是100分的暂时没有想出来,T1暴力只有30~60。 但是T3很不一样,像一个极其简单...

weixin_38168696的博客 128

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

LFM2.5-1.2B-Thinking体验:内存不到1GB的惊艳文本生成

本文介绍了如何在星图GPU平台上自动化部署【ollama】LFM2.5-1.2B-Thinking镜像,实现低资源消耗下的高质量文本生成。该轻量级思考模型仅需约1GB内存,支持逻辑推演与多步验证,适用于教育备课、职场文案撰写、边缘设备本地AI助手等典型场景。

weixin_31597759的博客 332

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

火灾黄金时间可计算吗?基于热解与通风的动态预警模型

火灾早期预警的核心在于‘黄金时间’——即从阴燃到不可控明火的关键窗口。它并非经验性的3分钟法则,而是由燃料热解动力学、空间通风条件、探测器响应特性等多物理场耦合决定的动态阈值。通过Kissinger方程量化热解活化能、ASHRAE通风系数建模气流影响、多光谱探测器响应函数(DRF)表征传感器时延,可构建具备工程落地能力的T_gold计算模型。该模型已通过UL 268A认证,在物流中心、数据中心等场景实现±3秒预测精度,并支持STM32边缘端轻量化部署。本文聚焦于将消防专家‘时间直觉’转化为可输入、可迭代、可

weixin_30411239的博客 357

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

黑暗森林系Psytrance音乐制作全解析:从声音设计到混音工程

电子音乐制作中,声音设计是塑造风格的核心环节,而混音工程则决定最终听感。从合成器波形选择到滤波器共振调制,再到侧链压缩与声场处理,每一步都直接影响作品的能量与层次。酸性贝斯、Kick与氛围Texture的配合,是打造深邃迷幻听感的关键。在Psytrance、Dark Psytrance等风格中,低频控制、立体声宽度和段落编排尤显重要。通过合理的DAW模板、效果器链和编组路由,制作人可以高效复现复杂音色结构。从一首黑暗系Forest作品出发,可完整拆解从声音设计、编曲递进到混音母带的工程化流程,为电子音乐制作

weixin_34007886的博客 380

一小时Ambient Techno Set制作全解析:从工程搭建到混音编排

在电子音乐创作中,Ambient Techno 是氛围音乐与Techno律动的融合,强调空间感和情绪流动。长时长作品(如一小时Set)的制作远比单曲复杂,其核心挑战在于维持听觉注意力,避免听觉疲劳。这涉及到音频工程中的自动化设计、频段分配、混音动态等核心技术。通过合理的轨道分组、参数自动化以及结构编排,可以构建出具有叙事感的音乐旅程。这种制作思维不仅适用于氛围电子乐,也广泛用于长时长混音、电台背景乐、声音设计等场景,帮助制作人打造连续、耐听且富有变化的听觉体验。本文以一小时Ambient Techno Se

weixin_34357887的博客 329
上一篇: Plotly深入浅出
下一篇: 40分钟吃掉DeepFM算法
算法美食屋
博客等级 码龄9年 2万+粉丝 154原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值