【深度学习系统】Lecture 2 - ML Refresher / Softmax Regression

一、问题的理解方式

首先,什么是数据驱动的编程?面对经典的MNIST数据集识别任务,传统的编程思维和数据驱动的编程思维有何不同?
在这里插入图片描述

  • 传统编程思维: 通常从明确的问题定义和具体的算法开始。对于 MNIST 数据集识别任务,可能会首先考虑使用特定的图像处理算法,如边缘检测、特征提取等,然后设计一系列的逻辑步骤来对图像进行处理和分类。
  • 数据驱动编程思维: 更注重对数据本身的理解。会先分析 MNIST 数据集的特点,包括图像的像素分布、数字的特征等。通过对数据的观察和探索,发现数据中的模式和规律,从而决定采用何种方法进行处理和分类。

然而即便是MNIST这样一种简单的数据集任务,用传统的编程思维通过人为设计一系列的逻辑步骤来解决也是十分地困难。于是人们尝试用计算机自动识别数据当中的模式,而非人为设定逻辑界定。那么如何让计算机学会学习就变成一件很本质的事情。以MNIST数据集为例,现在我有一堆图片数据,以及它的分类标签。 f ( picture i ) = label i f(\text {picture}_i)=\text{label}_i f(picturei)=labeli关键的任务是要设计一种学习算法,让计算机能够随着数据的不断增加,自己自动能够朝着一个方向找到这个所谓的分类函数 f f f

在统计当中,我们管 f f f叫做模型;通常假设的模型都会有参数;既然有参数,那么我们必然要做的一件事情就是估计模型的参数,也就是参数估计。估计得是好还是坏,我们需要有一个评判标准,也就是要有损失函数。我们当然希望能够尽可能好地估计参数,那么就需要使它的损失函数更小,也就是要做优化。这就是整套机器学习的流程,所以为什么说机器学习是一门数据驱动的编程,因为它的底层逻辑就是统计,而统计就是一门研究如何从数据当中发现规律的学科。

二、Softmax Regression

softmax regression是一种最简单的机器学习算法,因为它基于线性假设。线性假设的本质就是说,标签是数据的一组加权求和。不过由于这里是多分类任务,这里不做这样的直接映射,而是首先映射到各个标签类的概率。再在外面套一层argmax函数即可。
f ( x ; θ ) = arg max ⁡ i = 0 , 1 , . . . , 9 h θ ( x ) = arg max ⁡ i ( θ T x ) f(x;\theta)=\argmax_{i=0,1,...,9} h_{\theta}(x)=\argmax_i(\theta^T x) f(x;θ)=i=0,1,...,9argmaxhθ(x)=iargmax(θTx)其中 θ ∈ R n × k , x ∈ R n \theta \in R^{n\times k},x\in R^n θRn×k,xRn,这里面 x x x其实是把图片拉伸成一维的向量。

引入矩阵能够进行批量化运算。大大提高运算效率。
X ∈ R m × n = [ x ( 1 ) T . . . x ( m ) T ] X\in R^{m\times n}=\begin{bmatrix}x^{T}_{(1)}\\ .\\.\\.\\x^{T}_{(m)} \end{bmatrix} XRm×n= x(1)T...x(m)T h θ ( X ) = [ h θ ( x ( 1 ) ) T . . . h θ ( x ( m ) ) T ] = [ x ( 1 ) T θ . . . x ( m ) T θ ] = X θ h_{\theta}(X)=\begin{bmatrix} h_{\theta}(x_{(1)})^T\\ .\\.\\.\\ h_{\theta}(x_{(m)})^T \end{bmatrix}=\begin{bmatrix} x_{(1)}^T\theta\\ .\\.\\.\\ x_{(m)}^T\theta \end{bmatrix}=X\theta hθ(X)= hθ(x(1))T...hθ(x(m))T = x(1)Tθ...x(m)Tθ =

损失函数:
L e r r ( h ( x ) , y ) = { 0 if argmax i h i ( x ) = y 1 otherwise L_{err}(h(x),y)=\begin{cases}0&\text{if argmax}_ih_i(x)=y\\1&\text{otherwise}\end{cases} Lerr(h(x),y)={01if argmaxihi(x)=yotherwise其中 y = { 0 , 1 , . . . , 9 } y=\{0,1,...,9\} y={0,1,...,9}是标签。这个损失函数对于我们挑选最优参数来说并不合适,因为它随着参数 θ \theta θ的变化是是离散变化的,求不了导,只能把 θ \theta θ的空间遍历完才能知道最优的 θ \theta θ,而这在离散数学当中是一个NP-hard的难题。

NP-hard之所难,就是因为当我们站在某一个 θ \theta θ点位的时候,我们手头上没有任何关于函数空间的信息。通常一般的函数优化为什么简单?不就是有梯度嘛,梯度告诉我们站在当前的点位,朝着哪个方向走使得函数变化的最快。即便它有着陷入局部极值的隐患,但起码我们有能够出的牌了。

所以我们需要选择一个能够求当前梯度的损失函数。
L e r r ( h ( x ) , y ) = − log ⁡ p ( label = y ) = − h y ( x ) + log ⁡ ∑ j = 1 k exp ⁡ ( h j ( x ) ) L_{err}(h(x),y)=-\log p(\text{label}=y)=\\-h_y(x)+\log \sum_{j=1}^k\exp (h_j(x)) Lerr(h(x),y)=logp(label=y)=hy(x)+logj=1kexp(hj(x))这就是所谓的交叉熵损失,其中, p ( label = i ) = exp ⁡ h i ( x ) ∑ j = 1 k exp ⁡ h j ( x ) = softmax ( h ( x ) ) i p(\text{label}=i)=\frac{\exp{h_{i}(x)}}{\sum_{j=1}^k \exp{h_j(x)}} =\text{softmax}(h(x))_i p(label=i)=j=1kexphj(x)exphi(x)=softmax(h(x))i

而我们要做的优化:
minimize θ 1 m ∑ i = 1 m L e r r ( h θ ( x ( i ) ) , y ( i ) ) = minimize θ 1 m ∑ i = 1 m L e r r ( θ T x ( i ) , y ( i ) ) \underset{{\theta}}{\text{minimize}}\frac{1}{m}\sum_{i=1}^m L_{err}(h_{\theta}(x_{(i)}),y_{(i)})=\\ \underset{{\theta}}{\text{minimize}}\frac{1}{m}\sum_{i=1}^m L_{err}(\theta^Tx_{(i)},y_{(i)}) θminimizem1i=1mLerr(hθ(x(i)),y(i))=θminimizem1i=1mLerr(θTx(i),y(i))现在我们手头有梯度这张牌,怎么用呢?现在 θ \theta θ是一个 n × k n\times k n×k的矩阵,以下 ∇ θ f ( θ ) \nabla_{\theta}f(\theta) θf(θ)是梯度信息矩阵:
∇ θ f ( θ ) = [ ∂ f ( θ ) ∂ θ 11 . . . ∂ f ( θ ) ∂ θ 1 k . . . ∂ f ( θ ) ∂ θ n 1 . . . ∂ f ( θ ) ∂ θ n k ] \nabla_{\theta}f(\theta)=\begin{bmatrix}\frac{\partial f(\theta) }{\partial \theta_{11}}...\frac{\partial f(\theta) }{\partial \theta_{1k}}\\...\\ \frac{\partial f(\theta) }{\partial \theta_{n1}}...\frac{\partial f(\theta) }{\partial \theta_{nk}} \end{bmatrix} θf(θ)= θ11f(θ)...θ1kf(θ)...θn1f(θ)...θnkf(θ) 我们可以采用逐步利用梯度来更新 θ \theta θ,使之朝着一个让损失函数减小的方向变动(矩阵减法就是对应位置相减):
θ = θ − α ∇ θ f ( θ ) \theta=\theta-\alpha\nabla_{\theta}f(\theta) θ=θαθf(θ)其中, α \alpha α我们称之为学习率,这样一个方法称为梯度下降法

在这里插入图片描述
学习率因为需要人为设定,称这类参数为超参数,跟 θ \theta θ的区别在于后者只需要随机给一个初始值,基本不会不影响学习结果,而学习率是需要人为精心设计的,并且会对学习结果产生较大的影响。

还有一个值得注意的问题就是,理论上最优的方式是每次更新参数时,计算的梯度都应该用上所有样本的信息,但是在实际中这样造成的时间消耗太大,毕竟一个epoch只更新了一次参数,这样的时间效率实在划不来。实际当中采用的是随机梯度下降,也就是将样本随机打乱以后,每次只选取一个batch的数据来计算梯度,并对参数及时更新。这样等到过了一遍epoch的时候,就能够更新好几轮参数,效率更高。
θ = θ − α 1 B ∑ i = 1 B ∇ θ L e r r ( h θ ( x ( i ) ) , y ( i ) ) \theta=\theta-\alpha\frac{1}{B}\sum_{i=1}^B\nabla_{\theta}L_{err}(h_{\theta}(x_{(i)}),y_{(i)}) θ=θαB1i=1BθLerr(hθ(x(i)),y(i))由于学习率的人为设定,我们很难做到一个epoch期间,参数的逐步更新能够就把损失函数降到最低,通常需要几个epoch才能做到损失函数的收敛。当损失函数收敛的时候,对应到参数空间,要么已经到最高海拔的山顶了,要么还在“高原”逗留。这个我们无从知晓。

最后还有一小片乌云摆在面前,那就是 ∇ θ L e r r ( h θ ( x , y ) ) ∈ R n × k \nabla_{\theta}L_{err}(h_{\theta}(x,y))\in R^{n\times k} θLerr(hθ(x,y))Rn×k怎么算?注意, L e r r ( h θ ( x ) , y ) L_{err}(h_{\theta}(x),y) Lerr(hθ(x),y)是一个复合函数 L h [ h θ ( x ) ] L_{h}[h_{\theta}(x)] Lh[hθ(x)],这个就需要用到高数的链式法则技巧。

  • 首先计算外层的 h h h
    ∂ L e r r ( h , y ) ∂ h i = ∂ ∂ h i ( − h y + log ⁡ ∑ j = 1 k exp ⁡ h j ) = − I ( i = y ) + exp ⁡ h i ∑ i = 1 k exp ⁡ h j = softmax ( h ) i − e y ( i ) \frac{\partial{L_{err}(h,y)}}{\partial h_i}= \frac{\partial}{\partial h_i}(-h_y+\log\sum_{j=1}^k\exp h_j)=\\ -I(i=y)+\frac{\exp h_i}{\sum_{i=1}^k\exp h_j}=\text{softmax}(h)_i-e^{(i)}_y hiLerr(h,y)=hi(hy+logj=1kexphj)=I(i=y)+i=1kexphjexphi=softmax(h)iey(i)故, ∇ h L e r r ( h , y ) = z − e y \nabla_{h}L_{err}(h,y)=z-e_y hLerr(h,y)=zey其中, z = softmax ( h ) ∈ R k × 1 z=\text{softmax}(h)\in R^{k\times 1} z=softmax(h)Rk×1
  • 再来计算内层 θ \theta θ
    ∂ h θ ( x ) ∂ θ = ∂ ∂ θ ( θ T x ) = x ∈ R n × 1 \frac{\partial h_{\theta}(x)}{\partial \theta}=\frac{\partial}{\partial \theta}( \theta^Tx)=x\in R^{n\times 1} θhθ(x)=θ(θTx)=xRn×1
  • 最后按照矩阵维度适配的顺序乘起来: ∇ θ L e r r ( h θ ( x ) , y ) = x ( z − e y ) T \nabla_{\theta}L_{err}(h_{\theta}(x),y)=x(z-e_y)^T θLerr(hθ(x),y)=x(zey)T

所以,进一步有: ∇ θ L e r r ( X θ , y ) = X T ( Z − I y ) ∈ R n × k \nabla_{\theta}L_{err}(X\theta ,y)=X^T(Z-I_y)\in R^{n\times k} θLerr(,y)=XT(ZIy)Rn×k,( R n × m ⋅ R m × k = R n × k R^{n\times m}·R^{m\times k }=R^{n\times k} Rn×mRm×k=Rn×k)

三、Homework 0

  • 作业hw0:github
  • 作业hw0:colab

simple_ml.py

import struct
import numpy as np
import gzip
try:
    from simple_ml_ext import *
except:
    pass


def add(x, y):
    """ A trivial 'add' function you should implement to get used to the
    autograder and submission system.  The solution to this problem is in the
    the homework notebook.

    Args:
        x (Python number or numpy array)
        y (Python number or numpy array)

    Return:
        Sum of x + y
    """
    ### BEGIN YOUR CODE
    return x + y
    ### END YOUR CODE


def parse_mnist(image_filename, label_filename):
    """ Read an images and labels file in MNIST format.  See this page:
    http://yann.lecun.com/exdb/mnist/ for a description of the file format.

    Args:
        image_filename (str): name of gzipped images file in MNIST format
        label_filename (str): name of gzipped labels file in MNIST format

    Returns:
        Tuple (X,y):
            X (numpy.ndarray[np.float32]): 2D numpy array containing the loaded 
                data.  The dimensionality of the data should be 
                (num_examples x input_dim) where 'input_dim' is the full 
                dimension of the data, e.g., since MNIST images are 28x28, it 
                will be 784.  Values should be of type np.float32, and the data 
                should be normalized to have a minimum value of 0.0 and a 
                maximum value of 1.0 (i.e., scale original values of 0 to 0.0 
                and 255 to 1.0).

            y (numpy.ndarray[dtype=np.uint8]): 1D numpy array containing the
                labels of the examples.  Values should be of type np.uint8 and
                for MNIST will contain the values 0-9.
    """
    ### BEGIN YOUR CODE
    # Read the image file
    with gzip.open(image_filename, 'rb') as img_file:
        img_file.read(16)  # Skip the header
        img_data = np.frombuffer(img_file.read(), dtype=np.uint8)  # Read the image data
        img_data = img_data.reshape(-1, 28*28).astype(np.float32)  # Reshape and convert to float32
        img_data /= 255.0  # Normalize to [0.0, 1.0]
    
    # Read the label file
    with gzip.open(label_filename, 'rb') as lbl_file:
        lbl_file.read(8)  # Skip the header
        lbl_data = np.frombuffer(lbl_file.read(), dtype=np.uint8)  # Read the label data
    
    return img_data, lbl_data
    ### END YOUR CODE


def softmax_loss(Z, y):
    """ Return softmax loss.  Note that for the purposes of this assignment,
    you don't need to worry about "nicely" scaling the numerical properties
    of the log-sum-exp computation, but can just compute this directly.

    Args:
        Z (np.ndarray[np.float32]): 2D numpy array of shape
            (batch_size, num_classes), containing the logit predictions for
            each class.
        y (np.ndarray[np.uint8]): 1D numpy array of shape (batch_size, )
            containing the true label of each example.

    Returns:
        Average softmax loss over the sample.
    """
    ### BEGIN YOUR CODE
    # Subtract the maximum value in each row (for numerical stability)
    Z_stable = Z - np.max(Z, axis=1, keepdims=True)
    
    # Compute log(sum(exp(z_i))) for each row
    log_sum_exp = np.log(np.sum(np.exp(Z_stable), axis=1))
    
    # Subtract z_y (the logit corresponding to the correct class)
    correct_class_logits = Z_stable[np.arange(Z.shape[0]), y]
    
    # Compute the loss as the average of log(sum(exp(z_i))) - z_y
    loss = np.mean(log_sum_exp - correct_class_logits)
    
    return loss
    ### END YOUR CODE


def softmax_regression_epoch(X, y, theta, lr = 0.1, batch=100):
    """ Run a single epoch of SGD for softmax regression on the data, using
    the step size lr and specified batch size.  This function should modify the
    theta matrix in place, and you should iterate through batches in X _without_
    randomizing the order.

    Args:
        X (np.ndarray[np.float32]): 2D input array of size
            (num_examples x input_dim).
        y (np.ndarray[np.uint8]): 1D class label array of size (num_examples,)
        theta (np.ndarrray[np.float32]): 2D array of softmax regression
            parameters, of shape (input_dim, num_classes)
        lr (float): step size (learning rate) for SGD
        batch (int): size of SGD minibatch

    Returns:
        None
    """
    ### BEGIN YOUR CODE
    num_examples, input_dim = X.shape
    num_classes = theta.shape[1]

    for i in range(0, num_examples, batch):
        # Extract the batch
        X_batch = X[i:i+batch]
        y_batch = y[i:i+batch]

        # Compute logits
        logits = np.dot(X_batch, theta)  # Shape: (batch_size, num_classes)

        # Apply softmax to logits
        logits_stable = logits - np.max(logits, axis=1, keepdims=True)
        exp_logits = np.exp(logits_stable)
        Z = exp_logits / np.sum(exp_logits, axis=1, keepdims=True)  # Z = softmax probabilities

        # Create a one-hot encoded version of y_batch
        I_y = np.zeros_like(Z)
        I_y[np.arange(batch if i + batch < num_examples else num_examples - i), y_batch] = 1  # I_y

        # Compute the gradient
        grad = np.dot(X_batch.T, (Z - I_y)) / X_batch.shape[0]

        # Update the parameters
        theta -= lr * grad
    ### END YOUR CODE

def relu(x):
    return np.maximum(0, x)

def relu_derivative(x):
    return (x > 0).astype(np.float32)

def nn_epoch(X, y, W1, W2, lr = 0.1, batch=100):
    """ Run a single epoch of SGD for a two-layer neural network defined by the
    weights W1 and W2 (with no bias terms):
        logits = ReLU(X * W1) * W2
    The function should use the step size lr, and the specified batch size (and
    again, without randomizing the order of X).  It should modify the
    W1 and W2 matrices in place.

    Args:
        X (np.ndarray[np.float32]): 2D input array of size
            (num_examples x input_dim).
        y (np.ndarray[np.uint8]): 1D class label array of size (num_examples,)
        W1 (np.ndarray[np.float32]): 2D array of first layer weights, of shape
            (input_dim, hidden_dim)
        W2 (np.ndarray[np.float32]): 2D array of second layer weights, of shape
            (hidden_dim, num_classes)
        lr (float): step size (learning rate) for SGD
        batch (int): size of SGD minibatch

    Returns:
        None
    """
    ### BEGIN YOUR CODE
    num_examples, input_dim = X.shape
    _, hidden_dim = W1.shape
    num_classes = W2.shape[1]

    for i in range(0, num_examples, batch):
        # Extract the batch
        X_batch = X[i:i+batch]
        y_batch = y[i:i+batch]

        # Forward pass
        Z1 = np.dot(X_batch, W1)  # Shape: (batch_size, hidden_dim)
        A1 = relu(Z1)            # Shape: (batch_size, hidden_dim)
        Z2 = np.dot(A1, W2)      # Shape: (batch_size, num_classes)
        
        # Compute softmax probabilities and loss
        logits_stable = Z2 - np.max(Z2, axis=1, keepdims=True)
        exp_logits = np.exp(logits_stable)
        softmax_probs = exp_logits / np.sum(exp_logits, axis=1, keepdims=True)
        
        # Create a one-hot encoded version of y_batch
        y_one_hot = np.zeros_like(softmax_probs)
        y_one_hot[np.arange(batch if i + batch < num_examples else num_examples - i), y_batch] = 1  # I_y

        # Compute the gradient for W2
        dL_dZ2 = (softmax_probs - y_one_hot) / X_batch.shape[0]
        dL_dW2 = np.dot(A1.T, dL_dZ2)  # Gradient w.r.t. W2
        
        # Compute the gradient for W1
        dL_dA1 = np.dot(dL_dZ2, W2.T) * relu_derivative(Z1)
        dL_dW1 = np.dot(X_batch.T, dL_dA1)  # Gradient w.r.t. W1

        # Update weights
        W2 -= lr * dL_dW2
        W1 -= lr * dL_dW1
    ### END YOUR CODE



### CODE BELOW IS FOR ILLUSTRATION, YOU DO NOT NEED TO EDIT

def loss_err(h,y):
    """ Helper funciton to compute both loss and error"""
    return softmax_loss(h,y), np.mean(h.argmax(axis=1) != y)


def train_softmax(X_tr, y_tr, X_te, y_te, epochs=10, lr=0.5, batch=100,
                  cpp=False):
    """ Example function to fully train a softmax regression classifier """
    theta = np.zeros((X_tr.shape[1], y_tr.max()+1), dtype=np.float32)
    print("| Epoch | Train Loss | Train Err | Test Loss | Test Err |")
    for epoch in range(epochs):
        if not cpp:
            softmax_regression_epoch(X_tr, y_tr, theta, lr=lr, batch=batch)
        else:
            softmax_regression_epoch_cpp(X_tr, y_tr, theta, lr=lr, batch=batch)
        train_loss, train_err = loss_err(X_tr @ theta, y_tr)
        test_loss, test_err = loss_err(X_te @ theta, y_te)
        print("|  {:>4} |    {:.5f} |   {:.5f} |   {:.5f} |  {:.5f} |"\
              .format(epoch, train_loss, train_err, test_loss, test_err))


def train_nn(X_tr, y_tr, X_te, y_te, hidden_dim = 500,
             epochs=10, lr=0.5, batch=100):
    """ Example function to train two layer neural network """
    n, k = X_tr.shape[1], y_tr.max() + 1
    np.random.seed(0)
    W1 = np.random.randn(n, hidden_dim).astype(np.float32) / np.sqrt(hidden_dim)
    W2 = np.random.randn(hidden_dim, k).astype(np.float32) / np.sqrt(k)

    print("| Epoch | Train Loss | Train Err | Test Loss | Test Err |")
    for epoch in range(epochs):
        nn_epoch(X_tr, y_tr, W1, W2, lr=lr, batch=batch)
        train_loss, train_err = loss_err(np.maximum(X_tr@W1,0)@W2, y_tr)
        test_loss, test_err = loss_err(np.maximum(X_te@W1,0)@W2, y_te)
        print("|  {:>4} |    {:.5f} |   {:.5f} |   {:.5f} |  {:.5f} |"\
              .format(epoch, train_loss, train_err, test_loss, test_err))



if __name__ == "__main__":
    X_tr, y_tr = parse_mnist("data/train-images-idx3-ubyte.gz",
                             "data/train-labels-idx1-ubyte.gz")
    X_te, y_te = parse_mnist("data/t10k-images-idx3-ubyte.gz",
                             "data/t10k-labels-idx1-ubyte.gz")

    print("Training softmax regression")
    train_softmax(X_tr, y_tr, X_te, y_te, epochs=10, lr = 0.1)

    print("\nTraining two layer neural network w/ 100 hidden units")
    train_nn(X_tr, y_tr, X_te, y_te, hidden_dim=100, epochs=20, lr = 0.2)

simple_ml_ext.cpp

#include <pybind11/pybind11.h>
#include <pybind11/numpy.h>
#include <cmath>
#include <iostream>

namespace py = pybind11;

void softmax_regression_epoch_cpp(const float *X, const unsigned char *y,
                                  float *theta, size_t m, size_t n, size_t k,
                                  float lr, size_t batch) 
{
    std::vector<float> logits(batch * k);       // Stores the logits
    std::vector<float> softmax(batch * k);      // Stores softmax probabilities
    std::vector<float> gradient(n * k);         // Stores the gradient for theta

    for (size_t i = 0; i < m; i += batch) {
        size_t cur_batch_size = std::min(batch, m - i);

        // Compute logits: Z = X_batch * theta
        for (size_t b = 0; b < cur_batch_size; ++b) {
            for (size_t j = 0; j < k; ++j) {
                logits[b * k + j] = 0.0f;
                for (size_t d = 0; d < n; ++d) {
                    logits[b * k + j] += X[(i + b) * n + d] * theta[d * k + j];
                }
            }
        }

        // Apply softmax to compute the probabilities
        for (size_t b = 0; b < cur_batch_size; ++b) {
            float max_logit = logits[b * k];
            for (size_t j = 1; j < k; ++j) {
                if (logits[b * k + j] > max_logit) {
                    max_logit = logits[b * k + j];
                }
            }

            // Subtract max_logit for numerical stability
            float sum_exp = 0.0f;
            for (size_t j = 0; j < k; ++j) {
                softmax[b * k + j] = std::exp(logits[b * k + j] - max_logit);
                sum_exp += softmax[b * k + j];
            }

            for (size_t j = 0; j < k; ++j) {
                softmax[b * k + j] /= sum_exp;
            }
        }

        // Compute the gradients and update theta
        std::fill(gradient.begin(), gradient.end(), 0.0f);

        for (size_t b = 0; b < cur_batch_size; ++b) {
            for (size_t j = 0; j < k; ++j) {
                float indicator = (j == y[i + b]) ? 1.0f : 0.0f;
                float error = softmax[b * k + j] - indicator;

                for (size_t d = 0; d < n; ++d) {
                    gradient[d * k + j] += X[(i + b) * n + d] * error;
                }
            }
        }

        // Update theta using the gradients
        for (size_t j = 0; j < n * k; ++j) {
            theta[j] -= lr * gradient[j] / cur_batch_size;
        }
    }
}



/**
 * This is the pybind11 code that wraps the function above.  It's only role is
 * wrap the function above in a Python module, and you do not need to make any
 * edits to the code
 */
PYBIND11_MODULE(simple_ml_ext, m) {
    m.def("softmax_regression_epoch_cpp",
    	[](py::array_t<float, py::array::c_style> X,
           py::array_t<unsigned char, py::array::c_style> y,
           py::array_t<float, py::array::c_style> theta,
           float lr,
           int batch) {
        softmax_regression_epoch_cpp(
        	static_cast<const float*>(X.request().ptr),
            static_cast<const unsigned char*>(y.request().ptr),
            static_cast<float*>(theta.request().ptr),
            X.request().shape[0],
            X.request().shape[1],
            theta.request().shape[1],
            lr,
            batch
           );
    },
    py::arg("X"), py::arg("y"), py::arg("theta"),
    py::arg("lr"), py::arg("batch"));
}

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

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

相关文章

AI时代的神器,解锁 PPT 制作新体验--分享使用经验

背景&#xff1a;探讨人们在使用AI工具时&#xff0c;最喜欢的和认为最好用的工具是哪些&#xff0c;展示AI技术的实际应用和影响。 说明&#xff1a;本文分析的AI技术的实际应用是制作PPT的AI工具。>>快速访问本文的AI工具<< 你好&#xff0c;我是三桥君 你有没有…

网络抓包06 - Socket抓包

TCP thread {val socket Socket("xx.xxx.xxx.xx", 8888)socket.soTimeout 3000val os socket.getOutputStream()Log.e("Socket", "class name ${os::class.java.canonicalName}")os.write(0x00)}运行代码&#xff0c;得知 OutputStream 是 S…

Python 工具库每日推荐 【sqlparse】

文章目录 引言SQL解析工具的重要性今日推荐:sqlparse工具库主要功能:使用场景:安装与配置快速上手示例代码代码解释实际应用案例案例:SQL查询分析器案例分析高级特性自定义格式化处理多个语句扩展阅读与资源优缺点分析优点:缺点:总结【 已更新完 Python工具库每日推荐 专…

文件的读写、FileStream

//现在在desktop\10.13文件夹下的读写文件,由上知空空如也。 if (File.Exists(@"C:\Users\11442\Desktop\10.13\FILE.txt")) { File.Delete(@"C:\Users\11442\Desktop\10.13\FILE.txt"); File.Create(@"C:\Users\11442\Desktop\10.13\FIL…

(IOS)VMware虚拟机上安装win10系统(超详细)

简介 虚拟机是一种软件实现的计算机系统&#xff0c;可以在现有的操作系统平台上运行一个或多个虚拟的操作系统。它通过在主机操作系统上创建一个虚拟的硬件平台&#xff0c;并在其上运行一个完整的操作系统&#xff0c;来模拟一个真实的物理计算机。虚拟机可以提供一种隔离的…

多线程代码案例

案例一.单例模式 单例模式是一种设计模式;类似于棋谱,有固定套路,针对一些特定场景可以给出一些比较好的解决方案; 只要按照设计模式来写代码,就可以保证代码不会太差,保证了代码的下限; --------------------------------------------------------------------------------…

接口测试面试题含答案

1、解释一下正向和逆向测试。 正向测试&#xff1a;针对接口设计预期的功能和行为&#xff0c;验证接口是否按照预期工作。 逆向测试&#xff1a;针对错误输入、不合理的条件或非预期的使用方式&#xff0c;验证接口是否能够适当地处理这些情况并提供合理的错误处理。 2、什…

Windows11下 安装 Docker部分疑难杂症(Unexpecter WSL error)

装了大半天Docker desktop终于装好了&#xff0c;网上有的主流教程就不复述了&#xff0c;主要说一下网上没有的教程。 以下是遇到的问题&#xff1a; 首先&#xff0c;启用或关闭Windows确保里面与虚拟机有关的几个都要选上 没有Hyper-V参考此文 但是我这里都勾选了&#x…

Unity/VS 消除不想要的黄色警告

方法一&#xff1a;单个消除 在要关闭的代码前一行写上#pragma warning disable 警告代码编码 在要关闭代码行下面一行写上#pragma warning restore 警告代码编码 精准的关闭指定地方引起的代码警告&#xff0c;不会过滤掉无辜的代码 #pragma warning disable 0162,1634HandleL…

react实现实时计时的最简方式

js中时间的处理&#xff0c;不借助于moment/dayjs这样的工具库&#xff0c;原生获取格式化的时间&#xff0c;最简单的实现方式可以参考下面这样。 实现效果 代码实现 封装hooks import { useState, useEffect } from "react";export function useCountTime() {c…

C语言笔记 14

函数原型 函数的先后关系 我们把自己定义的函数isPrime()写在main函数上面 是因为C的编译器自上而下顺序分析你的代码&#xff0c;在看到isPrime的时候&#xff0c;它需要知道isPrime()的样子——也就是isPrime()要几个参数&#xff0c;每个参数的类型如何&#xff0c;返回什么…

图解C#高级教程(五):枚举器和迭代器

本章主要介绍 C# 当中枚举器、可枚举类型以及迭代器相关的知识。 文章目录 1. 枚举器和可枚举类型2. IEnumerator 和 IEnumerable 接口2.1 IEnumerator 接口2.2 IEnumerable 接口 3. 泛型枚举接口4. 迭代器4.1 使用迭代器创建枚举器4.2 使用迭代器创建可枚举类4.3 迭代器作为属…

uni-app 打包成app时 限制web-view大小

今天对接一个uni-app的app 内置对方h5 web-view的形式 需要对方在web-view顶部加点东西 对方打的app的web-view始终是全屏的状态&#xff0c;对方表示做不到我要的效果 emmmmmm。。。。。。 于是乎 自己搭了个demo 本地h5跑起来审查了下代码&#xff0c;发现web-view是给绝对定…

IP地址与CDN提升网络速度

视频流媒体、在线游戏、或是电商购物&#xff0c;互联网在我们的工作生活中愈加不可或缺&#xff0c;人们对于网络的加载速度要求也越来越严苛。而IP地址与CDN的协同工作&#xff0c;对于互联网速度增加与稳定起这重大的作用。 一、CDN的工作原理 CDN是由分布在全球各地的服务…

基于JAVA+SpringBoot+Vue的旅游管理系统

基于JAVASpringBootVue的旅游管理系统 前言 ✌全网粉丝20W,csdn特邀作者、博客专家、CSDN[新星计划]导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末附源码下载链接&#x1f345; 哈喽兄…

使用XML实现MyBatis的基础操作

目录 前言 1.准备工作 1.1⽂件配置 1.2添加 mapper 接⼝ 2.增删改查操作 2.1增(Insert) 2.2删(Delete) 2.3改(Update) 2.4查(Select) 前言 接下来我们会使用的数据表如下&#xff1a; 对应的实体类为&#xff1a;UserInfo 所有的准备工作都在如下文章。 MyBatis 操作…

【论文速看】DL最新进展20241015-目标检测、图像超分

目录 【目标检测】【图像超分】 【目标检测】 [ECCV2024] LaMI-DETR: Open-Vocabulary Detection with Language Model Instruction 论文链接&#xff1a;https://arxiv.org/pdf/2407.11335 代码链接&#xff1a;https://github.com/eternaldolphin/LaMI-DETR 现有方法通过利…

Android ImageView scaleType使用

目录 一、src设置图片资源 二、scaleType设置图片缩放类型 三、scaleType具体表现 matrix&#xff1a; fitXY: fitStart&#xff1a; fitCenter&#xff1a; fitEnd: Center&#xff1a; centerCrop: centerInside&#xff1a; 控制ImageView和图片的大小保持一致…

【优选算法】(第四十一篇)

目录 被围绕的区域&#xff08;medium&#xff09; 题目解析 讲解算法原理 编写代码 迷宫中离⼊⼝最近的出⼝&#xff08;medium&#xff09; 题目解析 讲解算法原理 编写代码 被围绕的区域&#xff08;medium&#xff09; 题目解析 1.题目链接&#xff1a;. - 力扣&a…

创建docker虚拟镜像,创建启动服务脚本

进入系统命令服务目录 编辑服务 [Unit] DescriptionDocker Application Container Engine Documentationhttps://docs.docker.com Afternetwork-online.target firewalld.service Wantsnetwork-online.target [Service] Typenotify ExecStart/usr/bin/dockerd ExecReload/bin/…