|
数学理论 线性指线性变换,y = w1*x1 + w2*x2 +...+wn*xn + b - xi是变量,n元一次变量,因变量,y因为它发生变化 - wi是权重 - b是偏置,也叫截距 这是个万能公式,如果你的变量足够多,可以近似表示任何事物之间的关系 线性变换是n元一次方程, 变量y 与 x(x1,x2,...,xn,1) 的一个 线性组合(w1,w2,...,wn,b) 近似成 正比关系/线性关系 - 而不与某个变量成线性关系 -
回归有几重含义:
1. 特指AI/统计学 中 连续/分类两大问题中的 连续问题,回归代表着连续,毕竟世界本质是连续的
2. 映射到本质,回到更底层,本源层面;
用1维数据构建一个线性组合/结构,描述一个事物,
反过来就是,将事物投影/映射到1维结构中,
不管一个事物多么复杂,都可以通过构建一个1维线性结构近似描述
复杂问题简单化,由高级/高维 回归 本质/低维
3. 空间有一个正交直角坐标系,每个维度都是线性的,
将各个维度的数据排成一列,就得到一个维线性结构,
这个结构可表示万物
4. 微分思想,任何高阶函数都可以通过微分化阶为一,用1维数据的积分表示
5. 量变达到质变,单个1维变量是简单的,三个臭皮匠却能抵上一个诸葛亮,当N多个变量出现时,可模拟万物
- 单个人的力量弱
- 团队的力量大,尤其是形成一定 组织/组合 之后力量更强
|
这世界本质是连续的,虽然有些事物有明显的类别之分,但那是无数亿年演化而来的
- 比如,地球是一个球体,是一个整体...
这世界的运行是有规律,事物在不断的运动中,是在规律附近按一定频率做着周期性运动
- 有规律是肯定,也有一定的随机性,观察事物的运动主要看其规律的那一部分,毕竟随机变化很难总结出共性...
- 比如,走路,抬脚与落地之间相互交替,
- 你可以短暂地抬脚,但最终还是要落地,甚至你可以坐飞机上天,但最终还是要落地的...
比如,机械摆钟,它可以来回摆动,
那是因为有力推动它,失去这股力,它最终是要停下的,毕竟没有永动机...
事物运动有频率,有中心,它们在不断地回归各自那个中心...
- 又不断地受外力影响偏离中心
- 如此循环往复地运动着...
回归指回到最核心的那个规律! 或者说是回归到各个力相互作用的那个合力的方向上!
至于分类/类别,可看作是连续性数据,即回归数值的一部分
什么是规律,是事物的特性,是事物独特结构/存在所展现出的性质
- 也就是说是事物独特的结构展示/表现出了某个性质/规律
- 当要找某个规律时,就可以找对应结构的事物
- 规律无法脱离客观存在的事物,它们是一体的,同时存在
- 比如,若这世间没有了物质,但不存在引力了,因为引力因物质而生...连物质都没有,从何发现万有引力这个规律?
所以观察/寻找 规律,就是观察事物,看它的运动,看它的结构...
以上仅个人理解,如有雷同,纯属巧合!
|
单个样本向量@权重向量 + 偏置 = 数值
单个样本矩阵@权重矩阵 + 偏置 = 数值
批次样本矩阵@权重矩阵 + 偏置向量 = 标签向量
深度学习的线性回归 AI中使用向量表示一个样本x(x1,x2,...,xn)(行向量),w(w1,w2,...,wn)(列向量) xw + b = y 深度学习的数据都是以批量形式存在的,一个批次X中有多个x X@w + b = y w与X每一行运算,然后映射到y, 等价于 批量数据X经过参数矩阵w转换,映射到向量y(y1,y2,...,yn) 每个样本x对应一个yi,所以X在前,W在后 相乘再相加
深度学习之中都是 相乘再相加
在[0,1]的尺度上,相乘相加,以这种方式不断地 融合变换
这有一种大道至简的感觉,不像机器学习那样,整合了高大上的理论或公式...
- 如此简洁的方式,却可以 模拟/拟合 万物
谁是变量,认是常量
x1,x2,...,xn 这组数形成一个向量,代表一个样本,是常量
w1,w2,...,wn 是权重,是算法自身要调整的值,这些值来自数据,是变量
算法的学习就是要找到一组合适的wi,与样本向量线性组合,映射到 某个类别
以上是训练过程,训练中需要学习参数
预测时,参数固定,参数与数据皆是常量
|
|
业务分析及数据处理 数据预处理:空值处理,归一化 模型,损失函数,优化器 模型定义:参数网络初始化, 计算方法 (不包含数据,数据只是流过参数网络) 损失函数设计:求极值,DL都是批次操作,实际是批次损失 极值的均值 模型参数优化方法设计:优化模型参数的方法 训练,预测 训练:调用优化方法优化参数 预测:利用训练时相关参数处理数据,然后输入模型得到模型输出 模型保存与交付:数据预数据过程及参数,模型(模型参数,模型网络结构) |
class Model(object):
"""
机器学习模型骨架
"""
def __init__(self, hyper_parameters):
"""
定义超参数
"""
self.hyper_parameters = hyper_parameters
def fit(self, X, y):
"""
训练过程
"""
pass
def predict(self, X):
"""
定义预测过程
"""
pass
|
|
|
tensor设置为requires_grad=True后,将被看作一个变量
zero_这种下划线写在单词末尾的方式,表示replace,
表示原地转换变量的值,而不是返回一个新变量
|
在 PyTorch 的自动微分系统中,
只有叶子张量(即那些直接由用户创建的张量,而不是通过其他张量计算得到的)的
.grad 属性会被填充梯度信息。
如果一个张量是通过其他张量的操作得到的,那么它就不是叶子张量,其 .grad 属性默认不会被填充。
import torch
w1 = torch.tensor(3.0,requires_grad=True)
b = torch.tensor(2.0,requires_grad=True)
y = w1*2 + b*1
y.backward()
if y.is_leaf: #用户直接创建的
print(y.grad)
else:
print("y is not a leaf tensor")
y is not a leaf tensor
求导的入口是标量
import torch
w1 = torch.randn(2,3,requires_grad=True)
b = torch.tensor(2.0,requires_grad=True)
y = w1*2 + b*1
y = y.sum()
y.backward()
if y.is_leaf: #用户直接创建的
print(y.grad)
else:
print("y is not a leaf tensor")
此时的y是由其他张量计算得到的,y.grad不会被填充梯度
但要注意,深度学习也并不是要对y求偏导,y对应损失函数,
y.backward() 是梯度反向传播,最终求导的是参数变量
w1.grad # tensor(2.)
|
import torch w1 = torch.tensor([1.0,1.0],requires_grad=True) b = torch.tensor(1.0,requires_grad=True) y = w1 + b # tensor([2., 2.], grad_fn= w1.grad # tensor([1., 1.]) b.grad # tensor(2.) w1有多个维度,每个维度都需要求一个偏导,皆被当作一个变量, 因为他们的系数永远一样,所以其梯度也一样 由于广播机制,变量b与w1的每个变量 进行了一次运算,相当于每个元素都有一个b,sum时相加了n次
import torch
w1 = torch.tensor([1.0,1.0,1.0],requires_grad=True)
b = torch.tensor(1.0,requires_grad=True)
y = w1 + b # tensor([2., 2.], grad_fn=)
loss = y.sum() #转为标量
loss.backward()
b.grad #tensor(3.)
一个向量+一个数值,实际上是向量中各个元素+该数值 或者 先将数值扩展n份,成为一个n维向量,再与前面的向量按位相加 由于b的梯度是累加的,每一次的相加运算,都会累加一次梯度 |
import torch w1 = torch.tensor(data=[0.1,0.2,0.3],requires_grad=True) w2 = torch.tensor(data=[0.01,0.02,0.03],requires_grad=True) b = torch.tensor(0.1,requires_grad=True) y = w1*3 + w2*2 + b loss = y.sum() loss.backward() print(b.grad.data) # tensor(3.) 多个变量相加时,可以看作先将所有的参数变量相加 最后再与b相加,如此与单变量相加的效果一致 |
|
|
|
数据格式:这里以交易数据为例 import torch import math batch_size = 128 # 批次 seq_len = 64 # 相邻交易个数 col_nums = 13 # 1行数据13列 embedding_dim = 128 # 特征变换维度 data = torch.randn(batch_size, seq_len, col_nums) from torch import nn #[*,in_features] -- [*,out_features] linear = nn.Linear(in_features=col_nums,out_features=embedding_dim) linear.weight.data.normal_(0, 0.1) x = linear(data) x.shape # torch.Size([128, 64, 128])
[*,in_features] -- [*,out_features]
Linear 变换的是矩阵是最后一维
linear.weight.data.normal_(0, 0.1)
- 约束了随机参数的范围
- 非必须
|
import sys
import random
import numpy as np
import math
import torch
from torch import nn
class pc:
batch_size = 64
min_seq_len=40
max_seq_len=100
col_nums = 13
embedding_dim=128
class_nums = 2
padding_index = 0
#[B,L,C],一个序列100条交易,一条交易13个特征/列
data = torch.randn(pc.batch_size,pc.max_seq_len,pc.col_nums)
w = nn.Parameter(torch.ones(in_feature, embedding_dim, dtype=torch.float32),requires_grad=True) b = nn.Parameter(torch.ones(embedding_dim, dtype=torch.float32), requires_grad=True) x = data@w #torch.Size([64, 100, 128]) x = x + b x.shape ##torch.Size([64, 100, 128])
这里的w是一个[in_feature, embedding_dim]矩阵
将矩阵[64,100,13]变换到[64,100,128]
|
|
|
|
|
|
|
import numpy as np from matplotlib import pyplot as plt from sklearn.model_selection import train_test_split import torch from sklearn.linear_model import LinearRegression from sklearn.datasets import make_regression # 随机生成的回归测试数据 X, y = make_regression(n_samples=2000, n_features=13) X.shape,y.shape #((2000, 13), (2000,)) X_train, X_test, y_train ,y_test = train_test_split(X, y, test_size=0.15, random_state=1) # 特征归一化 mean_ = X_train.mean(axis=0) std_ = X_train.std(axis=0) # 处理训练数据 X_train = (X_train - mean_) / std_ # 处理测试数据 X_test = (X_test - mean_) / std_ lr1 = LinearRegression() lr1.fit(X=X_train, y=y_train)
#参数w
lr1.coef_[:3]
array([95.26287774, 15.38262642, 74.11799156])
#偏置b
lr1.intercept_
-5.381843234898983
lr1.predict(X=X_test)[:3],y_test[:3]
(array([ -97.28120707, -95.63686668, -147.64895265]),
array([ -97.28120707, -95.63686668, -147.64895265]))
机器学习中标签为向量,shape=(n,)
尝试学习中标签为矩阵,shape=(n,1)
y_test.shape #(300,)
|
import numpy as np
from matplotlib import pyplot as plt
from sklearn.model_selection import train_test_split
import torch
from sklearn.linear_model import LinearRegression
from sklearn.datasets import make_regression
# 随机生成的回归测试数据
X, y = make_regression(n_samples=2000, n_features=13)
X.shape,y.shape #((2000, 13), (2000,))
X_train, X_test, y_train ,y_test = train_test_split(X, y, test_size=0.15, random_state=1)
"""
数据转tensor
"""
# 检测是否有GPU
device = "cuda:0" if torch.cuda.is_available() else "cpu"
X_train1 = torch.tensor(data=X_train).to(dtype=torch.float64).to(device=device)
y_train1 = torch.tensor(data=y_train).to(dtype=torch.float64).to(device=device)
X_test1 = torch.tensor(data=X_test).to(dtype=torch.float64).to(device=device)
y_test1 = torch.tensor(data=y_test).to(dtype=torch.float64).to(device=device)
y_train1=y_train1.reshape(-1,1)
y_test1=y_test1.reshape(-1,1)
模型及参数,损失函数
def linear_regression(X, w, b):
"""线性回归(计算逻辑)
"""
return X @ w + b
def loss_fn(y_pred, y_true):
"""mse损失函数
"""
return ((y_pred - y_true) ** 2).mean()
#随机初始化模型的参数
w = torch.randn(13, 1, requires_grad=True, dtype=torch.float64, device=device)
b = torch.randn(1, requires_grad=True, dtype=torch.float64, device=device)
w.shape,b
(torch.Size([13, 1]),
tensor([1.9541e-14], dtype=torch.float64, requires_grad=True))
模型参数不在于大小,随机初始化即可
在于shape,要与数据X能进行矩阵运算
参数要将一个样本向量的n个维度[n1,n2,...,nn]变换到一个维度上[类别]
def predict(X, w, b):
with torch.no_grad():
y_pred = linear_regression(X=X, w=w, b=b)
return y_pred
训练
lr = 1e-2
for epoch in range(10000):
# 正向传播 --- 模型输出,预测结果
y_pred = linear_regression(X=X_train1, w=w, b=b)
# 计算损失 --
loss = loss_fn(y_pred=y_pred, y_true=y_train1)
# 反向传播 -- 求w和b的偏导数
loss.backward()
# 更新参数
w.data -= lr * w.grad
b.data -= lr * b.grad
# 清空梯度
w.grad.data.zero_()
b.grad.data.zero_()
# 过程监控
if epoch % 1000 == 0:
print(loss.item())
32887.253607779305
9.500932702751085e-13
5.664800872938198e-25
5.666899667315686e-25
5.666979629969325e-25
5.66737335508748e-25
5.6672913877990685e-25
5.6672913877990685e-25
5.666897662680915e-25
5.666897662680915e-25
predict(X=X_test1, w=w, b=b)[:3]
tensor([[ 209.9008],
[ -86.7581],
[-154.0384]], dtype=torch.float64)
y_test1[:3]
tensor([[ 209.9008],
[ -86.7581],
[-154.0384]], dtype=torch.float64)
w[:3]
tensor([[1.2952e+01],
[2.0628e-14],
[1.1275e+01]], dtype=torch.float64, grad_fn=
|
|
```
import torch
from ai.datasets import load_boston
# -------------------------------------------------
# 数据预处理
# -------------------------------------------------
def get_data():
X_train,y_train, X_test, y_test = load_boston()
# 从训练集中提取参数
mean_ = X_train.mean(axis=0) # 按列方向取均值,
std_ = X_train.std(axis=0) # 相同特征的一列数据归一
# 预处理训练集和测试集
X_train1 = (X_train - mean_) / std_
X_test1 = (X_test - mean_) / std_
# 共享内存
X_train = torch.from_numpy(X_train1).float()
X_test = torch.from_numpy(X_test1).to(dtype=torch.float32)
# 标签转列向量
y_train = torch.from_numpy(y_train.reshape((-1, 1))).float()
y_test = torch.from_numpy(y_test.reshape((-1, 1))).float()
return X_train,y_train, X_test, y_test
# -------------------------------------------------
# 模型构造
# -------------------------------------------------
class LinearRegression(object):
"""模型构造:线性回归
"""
loss = None
def __init__(self, device=None) -> None:
if device:
self.device = device
else:
# 若存在GPU则使用GPU
self.device = "cuda:0" if torch.cuda.is_available() else "cpu"
# 定义模型的参数
self.w = torch.randn(13, 1, requires_grad=True, dtype=torch.float32, device=device)
self.b = torch.randn(1, requires_grad=True, dtype=torch.float32, device=device)
# print(b) # tensor([0.1403], requires_grad=True)
# stp(b,"b") # shape:torch.Size([1]), type:class 'torch.Tensor', b
def forward(self, X):
return X@self.w + self.b
# -------------------------------------------------
# 损失函数设计
# -------------------------------------------------
@classmethod
def loss_fn(cls, y_pred, y_true):
cls.loss = ((y_pred - y_true) ** 2).mean()
return cls.loss
def grad_reduce(self, learning_rate):
"""梯度下降法
一种优化方法,让模型输出不断接近真实标签的方法
梯度指导数
"""
# 使用导数优化更新参数
self.w.data -= learning_rate * self.w.grad.data
self.b.data -= learning_rate * self.b.grad.data
# 清空梯度,以防止不断累加
self.w.grad.data.zero_()
self.b.grad.data.zero_()
def print_loss(self):
print(self.loss.item())
def train(self, X,y, learning_rate, loss_fn=None):
"""训练
每训练一次,就优化一次参数
"""
# 正向传播
y_pred = self.forward(X=X)
# print("y pred",y_pred[1],"y label",y_train[1])
# 模型预测与真实标签间的差异
if loss_fn:
loss = loss_fn(y_pred, y)
else:
loss = self.loss_fn(y_pred=y_pred, y_true=y_train)
# 反向传播,逆向求偏导grad
loss.backward()
model.grad_reduce(learning_rate=learning_rate)
def predict(self, X):
"""
模型预测
"""
with torch.no_grad():
y_pred = self.forward(X=X)
return y_pred
def batch_train(model, X, y, learning_rate=1e-2, epochs=300):
"""训练
梯度下降法求函数极值
"""
for epoch in range(epochs):
model.train(X=X,y=y, learning_rate=learning_rate)
# 过程监控
model.print_loss()
if __name__=="__main__":
X_train,y_train, X_test, y_test = get_data()
# from ai.box.base import stp
# stp(y_test,"y_test") # shape:torch.Size([76, 1]), type:class 'torch.Tensor', y_test
# print(y_test.dtype) # torch.float32
# 若存在GPU则使用GPU
device = "cuda:0" if torch.cuda.is_available() else "cpu"
X_train.to(device=device)
y_train.to(device=device)
X_test.to(device=device)
y_test.to(device=device)
model = LinearRegression()
batch_train(model=model,X=X_train,y=y_train)
"""
587.739013671875
545.857666015625
510.1678161621094
......
23.185871124267578
23.183822631835938
23.181793212890625
"""
y_pred = model.predict(X=X_test)
print(y_pred)
"""
tensor([[17.6774],
[25.3967],
[36.5577],
...
...
...
[28.7579],
[29.5272],
[32.7000]])
"""
```
重点分析: 1. 模型定义:X@self.w + self.b 2. 损失函数设计: MSE,((y_pred - y_true) ** 2).mean() |
|
|
|
|
import numpy as np
import torch
from torch import nn
import torch.nn.functional as F
# torch 批次处理
from torch.utils.data import Dataset
from torch.utils.data import DataLoader
from sklearn.datasets import make_regression
from sklearn.model_selection import train_test_split
# 因为加入了1%的噪声,所以,不管怎么训练,模型的精度上限是 99%,会有稍许浮动,但不会达到100%
# 这也说明影响精度的两个重要因素:一是模型算法不够好,二是数据噪声太多(这个决定了上限)
X,y = make_regression(n_samples=10000,n_features=100,noise=0.01,random_state=73)
X_train, X_test, y_train, y_test = train_test_split(X,y,test_size=0.1,random_state=73)
class MyDataSet(Dataset):
def __init__(self,X,y):
"""
构建数据集
"""
self.X = X
self.y = y.reshape(-1,1)
print(f"seq_len={len(X[0])}")
def __len__(self):
return len(self.X)
def __getitem__(self, idx):
x = self.X[idx]
y = self.y[idx]
return torch.tensor(data=x).float(), torch.tensor(data=y).float()
# 自定义数据加载器
train_dataset = MyDataSet(X=X_train,y=y_train)
test_dataset = MyDataSet(X=X_test,y=y_test)
# -----------------------------
# 模型定义
# -----------------------------
class LinearModel(nn.Module):
def __init__(self, in_features=100, out_features=1):
"""初始化网络参数"""
super().__init__()
self.linear = nn.Linear(in_features=in_features, out_features=out_features)
def forward(self, X):
"""让数据流过参数网络"""
x = self.linear(X)
return x
#模型
model = LinearModel(in_features=100, out_features=1)
#损失函数
loss_fn = nn.MSELoss()
#优化器
optim = torch.optim.Adam(params=model.parameters(),lr=1e-3)
# 从数据集中批次取数据
train_dataloader = DataLoader(dataset=train_dataset, shuffle=True, batch_size = 128)
# 训练一行数据,测试代码是否有误
for X,y in train_dataloader:
print(X.shape,X.ndim,y.shape,y.ndim) # torch.Size([128, 100]) 2 torch.Size([128, 1]) 2
y_out = model(X)
if y_out.ndim != y.ndim:
print('模型输出数据维度与标签维度不一致,无法进行损失计算...')
print('y_out:',y_out.shape,y_out.ndim) # torch.Size([128, 1]) 2
break
loss = loss_fn(y_out,y)
optim.zero_grad()
loss.backward()
optim.step()
break
# ------------------
# 重要:参数网络定义(模型定义),如何让参数逼近标签(损失函数设计及优化方法)
# ------------------
|
|
数据集 from tpf.dl import MyDataSet from tpf.dl import log from tpf.dl import DMEval import numpy as np import torch from torch import nn # torch 批次处理 from torch.utils.data import Dataset from torch.utils.data import DataLoader from sklearn.datasets import make_regression from sklearn.model_selection import train_test_split # 因为加入了1%的噪声,所以,不管怎么训练,模型的精度上限是 99%,会有稍许浮动,但不会达到100% # 这也说明影响精度的两个重要因素:一是模型算法不够好,二是数据噪声太多(这个决定了上限) X,y = make_regression(n_samples=10000,n_features=100,noise=0.01,random_state=73) X_train, X_test, y_train, y_test = train_test_split(X,y,test_size=0.1,random_state=73) device = "cuda:0" if torch.cuda.is_available() else "cpu" # 自定义数据加载器 train_dataset = MyDataSet(X=X_train,y=y_train) test_dataset = MyDataSet(X=X_test,y=y_test) 模型,损失函数,优化器 # ----------------------------- # 模型定义 # ----------------------------- from tpf.dl import LinearModel #模型 model = LinearModel(in_features=100, out_features=1) #损失函数 loss_fn = nn.MSELoss() #优化器 optim = torch.optim.Adam(params=model.parameters(),lr=1e-3) # 从数据集中批次取数据 # train_dataloader = DataLoader(dataset=train_dataset, shuffle=True, batch_size = 128) 训练
from tpf.dl import T
T.train(model=model,
loss_fn=loss_fn,
optimizer="adam",
train_dataset=train_dataset, test_dataset=test_dataset,
epochs=3,
batch_size=128,
learning_rate=1e-3,
model_param_path="ml_model1_params.h5",
auto_save=True,
continuation=True, #是否在之前训练的基础上进行训练
is_regression=True,
log_file="/tmp/train.log")
|
|
|
|
|
X@w + b
代码虽然只有一行,需要注意的地方有很多:
1 X是多个样本形成的批次,行代表样本的个数,
2 列代表不同的特征
3 w为列向量,b为标量
4 X@w表示X通过w进行映射,即X中的每一行通过w进行映射,或者说w对X的特征进行变换
5 数据X在左侧,参数矩阵w在矩阵乘法的右侧,
6 本质是每一行都与列向量w进行向量内积运算:相乘再相加,化为一个标量(一个数),
由于有N行,所以形成一个列向量,实际每个样本被转化成了标量,降了一维
表示从列向量w的角度从样本中提取出一个维度的数据
7 广播进制,b是标量,标量与矩阵一起运算存在广播机制,但这里每行的x与w运算后也化成了一个标量,所以每行b被运算了一次
但X是有多行的,所以整个表达式b被加到了X的每一行上,b被运算的次数为X的行数
8 AI中永远一个样本对应一个预测结果,
X批次的维度,这里是行,这个维度永远不会变,
即不管怎么预测,有多少个样本就会出多少个结果
9 这一步的X,就是能与参数做矩阵乘法的X,必定是经过预处理的X
10 AI中与X成对出现的标签y,没有在这个表达式中,也就是说标签不参与模型计算,哪标签在哪算?
11 标签参与损失函数的计算,损失函数衡量模型输出与标签之间的差异,即标签比较的对象是这个表达式本身
12 不知你是否质疑过b为什么是一个标量,为什么不定义成列向量,
如果是列向量,即为每个样本定义一个不同的b,这样有违AI的核心,
AI求的是那个参数矩阵,对所有样本都适用的参数矩阵,求的是共性
只属于某个样本,而不是一类样本的特征,AI有专门的名词来形容:过拟合,这是我们要避免的
在y=ax+b这样的一元一次线性方程中,从解析几何的角度看,ax决定的是函数的倾斜度,b表示对函数图形整体做上下移动
即b的作用是在不改变函数结构的情况下,使之更接近标签数据
13 表达式整体是线性回归,矩阵相乘,是向量内积,是线性代数那本书的核心,是深度学习中全连接/神经网络层的别名
14 回归是连续的数据,但X可是离散型数据,这是怎么预测出连续的结果的,原理何在?
这得用大片文字解释,也是AI的一个重要环节,并且还比较抽象,此处暂时忽略,不然这文章都写不完了....
15 看到矩阵相乘,要立即确定两个点:1 每个矩阵的shape, 2 是否存在广播机制
16 X@w+b是模型算法,它的shape决定了标签要转化的shape,因为它将来要与标签求损失,
最好让标签的shape与模型输出的shape一致,否则广播机制就会生效,
17 模型算法可以有多个变量形成一个参数矩阵,比如w,但将来定义的损失函数的结果loss_fn=f(w1,w2,...,wn)是一个标量
由于参与运算的都是矩阵,所以自定义损失函数矩阵运算之后,其结果通常不是一个标量,
需要确认这一点,然后将之转化为标量,变量可以多个维度,损失结果我们只要一个值就可以了
18 终极目的:就是我们在干什么,为了什么?我们为了将业务数据从一个维度转换到另外一个业务维度,
从纯数据的角度看,就是对数据完成了一次线性变换,将数据从一个维度变换到另外一个维度
怎么实现的?就是矩阵相乘,
将业务映射为数据,通过矩阵相乘提取某个维度的数据,
后续再通过一些优化方法,使这样的变换更加准确
19 X@w+b线性回归模型的表达能力是有上限的,并且不高,只能处理一些简单的问题;
所以复杂问题就不要用这个,但简单问题用简单方法解决也并无问题
20 批次处理。本质就是个向量内积,多个向量放一起,形成多行就有了批次,
批次这个维度这里是行(X的第1维)还可以是列(X的第2维),具体要看处理什么样的数据,
这里,你的脑海中应该有一行行的数据与w进行相乘再相加的操作,转化为一个个数字,
这些数字按批次的维度排列...数据从一个维度转换到了另外一个维度,这么一个画面
而不是像没接触过矩阵那样,潜意识认为X只是一个数字,
21 计算图。深度学习框架解决的主要问题是自动求导,解决方式就是计算图;
以pytorch为例,从import torch这一行开始,计算图就开始构建了
如果你想要一段不进行自动求导的代码,比如预测的时候,需要加上
with torch.no_grad():
y_pred = X@w+b
由于是框架自动实现的,这一点极容易被忽略;
计算图自动求导,广播机制 是深度学习矩阵运算容易被忽略的两个地方
x = x - h h 是y = model(x)在x处的导数再乘一个比较小的正数 导数可以反应函数的变化趋势,可以从大量数据中快速找到区域极值,即导数为0的地方 x - h, 如果函数曲线是下降趋势,那么h为负,表示当前位置未过极值,x-h就是加上一个正数,表示向前一小步 如果函数曲线是上升趋势,那么h为正,表示当前位置过了极值,x-h就是加上一个负数,表示退后一小步 这意味着随机从函数上取一点,一步步走下去,总会逼近一个极值,这就是我们需要的 深度学习的核心问题,是快速 快速 快速求出极值,数学上转化为求导问题 数学上的求导,可以一次对N个变量求导,此时又叫求偏导 核心是导数可以反应函数的变化趋势,在数字上体现为有正负 它是多大不是重点,要确保的是乘上一个较小的数,其结果h不要太大,即一次跳过的长度不要太大 重点是它有正负 这个正负让 x-h 这个表达式可以从函数的任意一点逼近它所在局部区域的极值 如果求导问题搞不定,深度学习就进行不下去,好在现在有很多框架实现了自动求导 难点在于x是向量,由n个变量组成,对x进行一次求导,就是求所有变量的导数(偏导数) x - h ,是x所有变量同时向各自区域附近的极值走一步
维度/特征 变换/转换
全连接,亦 线性变换, 将 数据/向量 的维数 变换到 另外一个维数 将数据的特征 从一个空间 映射到 另外一个空间