第二节-线性模型【跟随 up 主 “刘二大人” 学习 pytorch】

第二节 --- 线性模型【跟随 up 主 “刘二大人” 学习 pytorch】

前言

  • 本专栏是我这个小菜鸡跟随 B 站 up 主 刘二大人 学习 pytorch 完成的课后作业,原视频请戳这里

题目

  • 使用模型 y = w ∗ x + b y=w*x+b y=wx+b 计算损失,还要 使用 matplotlib 绘制 3D 图像

分析

  1. 首先,我们需要训练集才能进行模型训练,我们就以视频中的例子,即
train_x = [1.0, 2.0, 3.0]
train_y = [2.0, 4.0, 6.0]
  1. 然后,我们以 w ∈ [ 0.0 ,   6.0 ] w \in [0.0,\,6.0] w[0.0,6.0] b ∈ [ − 6.0 ,   6.0 ] b \in [-6.0,\,6.0] b[6.0,6.0] 为例,因为有两个变量,wb,所以我们使用双层循环遍历他们的每一个组合,并计算预测值与真实值之间的均差,即 loss,使用 DataFrame 存取数据,代码如下
import numpy as np
import pandas as pd

def forward(w, x, b):
	return w * x + b

def process(w, x, b, y):
	y_pred = forward(w, x, b)
	return pow(y_pred - y, 2)
	
w_list = np.arange(0.0, 6.1, 0.1) # arange 左闭右开
b_list = np.arange(-6.0, 6.1, 0.1)

result = []
for w_index, w in enumerate(self.w):
	for b_index, b in enumerate(self.b):
	    losses = pd.Series([0.0])
	    for x, y in zip(self.X, self.y):
	        losses = losses.append(pd.Series(process(w, x, b, y)))
	    result.loc[result.shape[0]+1] = (w, b, losses.std())
print(result)

---------------------------------
 	w 	b 	loss
1 	-6.0 	-6.0 	390.969735
2 	-6.0 	-5.9 	388.531712
3 	-6.0 	-5.8 	386.101901
4 	-6.0 	-5.7 	383.680285
5 	-6.0 	-5.6 	381.266851
... 	... 	... 	...
14637 	6.0 	5.6 	132.347889
14638 	6.0 	5.7 	133.795879
14639 	6.0 	5.8 	135.252733
14640 	6.0 	5.9 	136.718468
14641 	6.0 	6.0 	138.193102
  1. 获得了数据以后,我们就要绘图了,我们使用 matplotlib 绘制 3D 图像,这里我选用 Axes3D,我们看一下官方样例
    在这里插入图片描述
    1. 看起来好像是需要三个 array ,其中 np.meshgrid 作用是将两个一维的转换成两个二维的
    2. 我的尝试
    x, y = np.meshgrid(result['w'], result['b'])
    z = result['loss']
    fig = plt.figure()
    ax = Axes3D(fig)
    fig.add_axes(ax)
    ax.plot_surface(x, y, z, rstride=1, cstride=1, cmap=cm.viridis)
    plt.show()
    
    1. 但是这样会报错
    ValueError: Argument Z must be 2-dimensional.
    
    1. 意思是变量 z 必须得是个二维的数组

bug 解决

  • 既然要二维的数组,那我 result['loss'].to_frame() 一下可以吗?
    1. 然后又报错了/(ㄒoㄒ)/~~
    shape mismatch: objects cannot be broadcast to a single shape
    
    1. 意思是没有办法对应维度,也就是说,z.shape 必须和 x.shape、y.shape 一致,那这还不好办?直接 reshape
    z = np.array(result['loss']).reshape(x.shape[0], -1) # -1 表示不晓得这个是多少,要根据数据量和已知维度来判断
    
    1. 绘图结果如下
      在这里插入图片描述
    2. 嘶,不太对的样子,按理说不应该有这么离谱的图像,出现这种结果可能的原因是 reshape 之后,z 轴的数据与 x 和 y 轴的数据不对应了
    3. 最后的解决办法,遍历遍历 yyds,虽然会很慢)
    z = []
    for x_,  y_ in zip(x, y):
        z_ = []
        for w, b in zip(x_, y_):
            loss = data[(data['w'] == w) & (data['b'] == b)]['loss'].values[0]
            z_.append(loss)
        z.append(z_)
    
  • 还有个问题是,x 和 y都是有重复数据的,所以先去重再升维度
x, y = np.meshgrid(data['w'].drop_duplicates(), data['b'].drop_duplicates())

代码展示

  • 我封装了一个类,还加上了进度条,所以看着有点复杂,但还好
  • 计算时以单个 x 和 y 计算
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib import cm
from mpl_toolkits.mplot3d import Axes3D

class train:
    
    def __init__(self, X, y, w_limit, b_limit, span=0.1):
        self.X = X
        self.y = y
        self.w = np.arange(w_limit[0], w_limit[1] + span, span)
        self.b = np.arange(b_limit[0], b_limit[1] + span, span)
        self.result = pd.DataFrame(columns=['w', 'b', 'loss'])
    
    # 预测
    def __forward(self, w, x, b):
        return w * x + b
    
    # 计算损失
    def __loss(self, w, x, b, y):
        y_pred = self.__forward(w, x, b)
        return pow(y-y_pred, 2)
    
    def process(self):
        for w in self.w:
        
            print('w = {:>.2f}'.format(w))
            
            for b_index, b in enumerate(self.b):
            
                losses = []
                count = b_index + 1
                
                for x, y in zip(self.X, self.y):
                    losses.append(self.__loss(w, x, b, y))
                self.result.loc[self.result.shape[0]+1] = (w, b, sum(losses) / len(losses))
                
                min_index = self.result[self.result['w'] == w].sort_values(by='loss').iloc[0]

                print('\r{:>6.2f}%: [{}{}] b={:>.2f} min_loss={:>.2f}'.format(
                    count / len(self.b) * 100,
                    '■' * int(count / len(self.b) * 20),
                    '□' * (20 - int(count / len(self.b) * 20)),
                    min_index['b'], min_index['loss']
                ), end='')
                
            print()
            
        print('loss: %f' % (self.result['loss'].std()))
    
    def get_result(self):
        return self.result
    
train_x = [1.0, 2.0, 3.0]
train_y = [2.0, 4.0, 6.0]
model = train(train_x, train_y, (-3.0, 6.0), (-6.0, 6.0), 0.1)
model.process()

data = model.get_result()
x, y = np.meshgrid(data['w'].drop_duplicates(), data['b'].drop_duplicates())
z = []
for x_,  y_ in zip(x, y):
    z_ = []
    for w, b in zip(x_, y_):
    	# 找到对应的 loss
        loss = data[(data['w'] == w) & (data['b'] == b)]['loss'].values[0]
        z_.append(loss)
    z.append(z_)
z = np.array(z)
fig = plt.figure()
ax = Axes3D(fig)
fig.add_axes(ax)
ax.plot_surface(x, y, z, rstride=1, cstride=1, cmap=cm.viridis)
plt.show()
  • 以整个 train_x 和 train_y 计算,类 train 改为如下
class train:
    
    def __init__(self, X, y, w_limit, b_limit, span=0.1):
        self.X = np.array(X) if type(X) == list else X
        self.y = np.array(y) if type(y) == list else y
        self.w = np.arange(w_limit[0], w_limit[1] + span, span)
        self.b = np.arange(b_limit[0], b_limit[1] + span, span)
        self.result = pd.DataFrame(columns=['w', 'b', 'loss'])
    
    def __forward(self, w, X, b):
        
        return w * X + b
    
    def __loss(self, y, y_pred):
        
        return pow(y - y_pred, 2)
    
    def process(self):
        for w in self.w:
            
            print('w = {:>.2f}'.format(w))
            
            for b_index, b in enumerate(self.b):
                
                count = b_index + 1
                
                y_pred = self.__forward(w, self.X, b)
                loss = self.__loss(self.y, y_pred)
                
                self.result.loc[self.result.shape[0]+1] = (w, b, loss.sum() / loss.shape[0])
                
                min_index = self.result[self.result['w'] == w].sort_values(by='loss').iloc[0]
                
                print('\r{:>6.2f}%: [{}{}] b={:>.2f} min_loss={:>.2f}'.format(
                    count / len(self.b) * 100,
                    '■' * int(count / len(self.b) * 20),
                    '□' * (20 - int(count / len(self.b) * 20)),
                    min_index['b'], min_index['loss']
                ), end='')
                
            print()
            
        print('loss: %f' % (self.result['loss'].std()))
    
    def get_result(self):
        
        return self.result
  • 运行结果(部分)如下
    在这里插入图片描述

在这里插入图片描述

  • 其中,紫色的那一条目测可见的线就是所有 w 和 b 对应的最小 loss
  • 成功完成作业!!!



结尾

以上就是我要分享的内容,因为学识尚浅,会有不足,还请各位大佬指正。
有什么问题也可在评论区留言。
在这里插入图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值