基于Pytorch构建的朴素神经网络+结合实际案例

# 导入模块
import torch
import os
import numpy as np
import pandas as pd
from tqdm import tqdm
import seaborn as sns
from pylab import rcParams
import matplotlib.pyplot as plt
from matplotlib import rc
from sklearn.model_selection import train_test_split
from sklearn.metrics import confusion_matrix,classification_report
from torch import nn,optim
import torch.nn.functional as F

sns.set(style='whitegrid',palette='muted',font_scale=1.2)
HAPPY_COLORS_PALETTE = ["#01BEFE", "#FFDD00", "#FF7D00", "#FF006D", "#93D30C", "#8F00FF"]
sns.set_palette(sns.color_palette(HAPPY_COLORS_PALETTE))
rcParams['figure.figsize'] = 12,6

np.random.seed(42)
torch.manual_seed(42)
<torch._C.Generator at 0x2c012576cd0>
df = pd.read_excel(r'F:\桌面\1131论文计划\数据\气候数据\端数据.xlsx')
df
雨量(mm)云量短波辐射(W/m²)地面太阳能辐射(W/m²)
00.0000000.0760820.0000.000
10.0000000.1660190.0000.000
20.0000000.1581380.0000.000
30.4442590.7756740.0000.000
40.5807040.7029880.0000.000
...............
16662.6768300.087764480.097576.898
16671.8790500.074139639.283768.179
16685.6037200.330152750.970902.385
16699.7711700.384817507.725610.096
16708.5956000.972438444.973534.691

1671 rows × 4 columns

df.shape
(1671, 4)
# df.iloc[0:4].apply(lambda x: x.mean(),axis=0)[0:4]
df[df.iloc[1:] == 0] = None
df = df.fillna(0)
target = []
p =([0.2, 0.8])
for i in range(len(df)):
    value= np.random.choice([0, 1], p = p)
    target.append(value)
df['target'] = target
df
雨量(mm)云量短波辐射(W/m²)地面太阳能辐射(W/m²)target
00.0000000.0760820.0000.0001
10.0000000.1660190.0000.0001
20.0000000.1581380.0000.0001
30.4442590.7756740.0000.0001
40.5807040.7029880.0000.0000
..................
16662.6768300.087764480.097576.8981
16671.8790500.074139639.283768.1791
16685.6037200.330152750.970902.3850
16699.7711700.384817507.725610.0961
16708.5956000.972438444.973534.6911

1671 rows × 5 columns

# 样本平衡性
sns.countplot(df.target)
C:\Users\kingS\anaconda3\envs\pytorch_gpu\lib\site-packages\seaborn\_decorators.py:43: FutureWarning: Pass the following variable as a keyword arg: x. From version 0.12, the only valid positional argument will be `data`, and passing other arguments without an explicit keyword will result in an error or misinterpretation.
  FutureWarning





<AxesSubplot:xlabel='target', ylabel='count'>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pSVTU2rx-1639363505727)(output_9_2.png)]

df.target.value_counts() / df.shape[0]
1    0.787552
0    0.212448
Name: target, dtype: float64

拆分数据集

X_train,X_test,y_train,y_test = train_test_split(df.iloc[:,0:4],df.iloc[:,4:5])
X_train
雨量(mm)云量短波辐射(W/m²)地面太阳能辐射(W/m²)
14990.5106660.198878289.87400348.32000
14260.0000000.570845284.09500341.37600
5370.2952730.700285158.36400190.29500
6420.0174100.974240707.54500850.20400
15510.0000000.395067866.134001040.77000
...............
10300.0000000.7894110.000000.00000
10902.5160900.000000495.54500595.46000
1330.0000000.060874662.38600795.94100
14851.2018800.5762121.484151.78339
12390.0000000.110398399.67100480.25500

1253 rows × 4 columns

数据类型转换

X_train = torch.from_numpy(X_train.to_numpy()).float()
X_test = torch.from_numpy(X_test.to_numpy()).float()
y_train = torch.squeeze(torch.from_numpy(y_train.to_numpy())).float()
y_test = torch.squeeze(torch.from_numpy(y_test.to_numpy())).float()
print(X_train.shape,y_train.shape)
print(X_test.shape,y_test.shape)
torch.Size([1253, 4]) torch.Size([1253])
torch.Size([418, 4]) torch.Size([418])

构建神经网络

class NaiveNet(nn.Module):

    # 初始化
    def __init__(self, n_features):
        super(NaiveNet, self).__init__()
        self.fc1 = nn.Linear(n_features,5) # nn.Linear(in_features = 64*64*3, out_features = 1)
        self.fc2 = nn.Linear(5,3)
        self.fc3 = nn.Linear(3,1)

    def forward(self,x):
        x = F.relu(self.fc1(x)) # Calculate the derivative
        x = F.relu(self.fc2(x)) # 也可以进行张量操作和计算
        return torch.sigmoid(self.fc3(x))

def ann_viz(model, view=True, filename="network.gv"):
    """Vizualizez a Sequential model.
    # Arguments
    model: A Keras model instance.
    view: whether to display the model after generation.
    filename: where to save the vizualization. (a .gv file)
    title: A title for the graph
    """
    from graphviz import Digraph
    import torch
    HAPPY_COLORS_PALETTE = ["#01BEFE", "#FFDD00", "#FF7D00", "#FF006D", "#93D30C", "#8F00FF"]
    input_layer = 0
    hidden_layers_nr = 0
    layer_types = []
    hidden_layers = []
    output_layer = 0
    layers = [layer for layer in model.modules() if type(layer) == torch.nn.Linear]

    for layer in layers:
        if layer == layers[0]:
            input_layer = layer.in_features
            hidden_layers_nr += 1
            if type(layer) == torch.nn.Linear:
                hidden_layers.append(layer.out_features)
                layer_types.append("Dense")
            else:
                raise Exception("Input error")
        else:
            if layer == layers[-1]:
                output_layer = layer.out_features
            else:
                hidden_layers_nr += 1
                if type(layer) == torch.nn.Linear:
                    hidden_layers.append(layer.out_features)
                    layer_types.append("Dense")
                else:
                    raise Exception("Hidden error")
        last_layer_nodes = input_layer
        nodes_up = input_layer
        
    g = Digraph("g", filename=filename)
    n = 0
    g.graph_attr.update(splines="false", nodesep="0.5", ranksep="0", rankdir='LR')
    # Input Layer
    with g.subgraph(name="cluster_input") as c:
        if type(layers[0]) == torch.nn.Linear:
            the_label = "Input Layer"
            if layers[0].in_features > 10:
                the_label += " (+" + str(layers[0].in_features - 10) + ")"
                input_layer = 10
            c.attr(color="white")
            for i in range(0, input_layer):
                HAPPY_COLORS_PALETTE = ["#01BEFE", "#FFDD00", "#FF7D00", "#FF006D", "#93D30C", "#8F00FF"]
                n += 1
                c.node(str(n))
                c.attr(labeljust="1")
                c.attr(label=the_label, labelloc="bottom")
                c.attr(rank="same")
                c.node_attr.update(
                    width="0.65",
                    style="filled",
                    shape="circle",
                    color=HAPPY_COLORS_PALETTE[3],
                    fontcolor=HAPPY_COLORS_PALETTE[3],
                )
    for i in range(0, hidden_layers_nr):
        with g.subgraph(name="cluster_" + str(i + 1)) as c:    
            HAPPY_COLORS_PALETTE = ["#01BEFE", "#FFDD00", "#FF7D00", "#FF006D", "#93D30C", "#8F00FF"]
            if layer_types[i] == "Dense":
                c.attr(color="white")
                c.attr(rank="same")
                the_label = f'Hidden Layer {i + 1}'
                if layers[i].out_features > 10:
                    the_label += " (+" + str(layers[i].out_features - 10) + ")"
                    hidden_layers[i] = 10
                c.attr(labeljust="right", labelloc="b", label=the_label)
                for j in range(0, hidden_layers[i]):
                    n += 1
                    c.node(
                        str(n),
                        width="0.65",
                        shape="circle",
                        style="filled",
                        color=HAPPY_COLORS_PALETTE[0],
                        fontcolor=HAPPY_COLORS_PALETTE[0],
                    )
                    for h in range(nodes_up - last_layer_nodes + 1, nodes_up + 1):
                        g.edge(str(h), str(n))
                last_layer_nodes = hidden_layers[i]
                nodes_up += hidden_layers[i]
            else:
                raise Exception("Hidden layer type not supported")
    with g.subgraph(name="cluster_output") as c:
        HAPPY_COLORS_PALETTE = ["#01BEFE", "#FFDD00", "#FF7D00", "#FF006D", "#93D30C", "#8F00FF"]
        if type(layers[-1]) == torch.nn.Linear:
            c.attr(color="white")
            c.attr(rank="same")
            c.attr(labeljust="1")
            for i in range(1, output_layer + 1):
                n += 1
                c.node(
                    str(n),
                    width="0.65",
                    shape="circle",                        
                    style="filled",
                    color=HAPPY_COLORS_PALETTE[4],
                    fontcolor=HAPPY_COLORS_PALETTE[4],
    
                )
                for h in range(nodes_up - last_layer_nodes + 1, nodes_up + 1):
                    g.edge(str(h), str(n))
                c.attr(label="Output Layer", labelloc="bottom")
                c.node_attr.update(
                    color="#2ecc71", style="filled", fontcolor="#2ecc71", shape="circle"
                )
        g.attr(arrowShape="none")
        g.edge_attr.update(arrowhead="none", color="#707070", penwidth="2")
        if view is True:
            g.view()
        return g
net = NaiveNet(X_train.shape[1])
ann_viz(net,view=True)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-c5cS2eR0-1639363505730)(output_22_0.svg)]

激活函数可视化

# ReLU函数
ax = plt.gca()
plt.plot(
  np.linspace(-1, 1, 5), 
  F.relu(torch.linspace(-1, 1, steps=5)).numpy()
)
ax.set_ylim([-1.5, 1.5]);

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cwDZ3pkn-1639363505732)(output_24_0.png)]

# sigmod函数
ax = plt.gca()

plt.plot(
  np.linspace(-10, 10, 100), 
  torch.sigmoid(torch.linspace(-10, 10, steps=100)).numpy()
)
ax.set_ylim([-0.5, 1.5]);

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-U0wXx7d0-1639363505733)(output_25_0.png)]

训练神经网络

criterion = nn.BCELoss()

优化器

optimizer = optim.Adam(net.parameters(),lr=0.001) # lr=learning rate

在GPU上计算

device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')

X_train = X_train.to(device)
y_train = y_train.to(device)

X_test = X_test.to(device)
y_test = y_test.to(device)

net = net.to(device)
criterion = criterion.to(device)

寻找最优参数

def calculate_accuracy(y_true,y_pred):
    predicted = y_pred.ge(.5).view(-1)
    return (y_true == predicted).sum().float() / len(y_true)

开始训练

def round_tensor(t, decimal_places=3):
    return round(t.item(), decimal_places)

for epoch in range(1000):    
    y_pred = net(X_train)
    y_pred = torch.squeeze(y_pred)
    train_loss = criterion(y_pred, y_train)
    
    if epoch % 100 == 0:
        train_acc = calculate_accuracy(y_train, y_pred)

        y_test_pred = net(X_test)
        y_test_pred = torch.squeeze(y_test_pred)

        test_loss = criterion(y_test_pred, y_test)
        test_acc = calculate_accuracy(y_test, y_test_pred)
        print(f'''epoch {epoch}
              Train set - loss: {round_tensor(train_loss)}, accuracy: {round_tensor(train_acc)}
              Test  set - loss: {round_tensor(test_loss)}, accuracy: {round_tensor(test_acc)}''')
    
    optimizer.zero_grad()  # 清零梯度缓存
    train_loss.backward() # 反向传播误差
    optimizer.step()  # 更新参数
epoch 0
              Train set - loss: 4.709, accuracy: 0.784
              Test  set - loss: 5.482, accuracy: 0.799
epoch 100
              Train set - loss: 0.556, accuracy: 0.784
              Test  set - loss: 0.548, accuracy: 0.799
epoch 200
              Train set - loss: 0.537, accuracy: 0.784
              Test  set - loss: 0.531, accuracy: 0.799
epoch 300
              Train set - loss: 0.528, accuracy: 0.784
              Test  set - loss: 0.524, accuracy: 0.799
epoch 400
              Train set - loss: 0.526, accuracy: 0.784
              Test  set - loss: 0.521, accuracy: 0.799
epoch 500
              Train set - loss: 0.525, accuracy: 0.784
              Test  set - loss: 0.519, accuracy: 0.799
epoch 600
              Train set - loss: 0.524, accuracy: 0.784
              Test  set - loss: 0.518, accuracy: 0.799
epoch 700
              Train set - loss: 0.524, accuracy: 0.784
              Test  set - loss: 0.517, accuracy: 0.799
epoch 800
              Train set - loss: 0.523, accuracy: 0.784
              Test  set - loss: 0.515, accuracy: 0.799
epoch 900
              Train set - loss: 0.523, accuracy: 0.784
              Test  set - loss: 0.514, accuracy: 0.799

保存模型

MODEL_PATH = 'model path'
torch.save(net,MODEL_PATH)

加载模型

net = torch.load(MODEL_PATH)

因为一个模型训练时间是很长的,所以有时候我们需要保存我们的模型,喜爱在继续加载进行来

评估

target1 = ['不好','好']

y_pred = net(X_test)
y_pred = y_pred.ge(.5).view(-1).cpu()
y_test = y_test.cpu()

print(classification_report(y_test,y_pred,target_names=target1))
              precision    recall  f1-score   support

          不好       0.00      0.00      0.00        84
           好       0.80      1.00      0.89       334

    accuracy                           0.80       418
   macro avg       0.40      0.50      0.44       418
weighted avg       0.64      0.80      0.71       418



C:\Users\kingS\anaconda3\envs\pytorch_gpu\lib\site-packages\sklearn\metrics\_classification.py:1308: UndefinedMetricWarning: Precision and F-score are ill-defined and being set to 0.0 in labels with no predicted samples. Use `zero_division` parameter to control this behavior.
  _warn_prf(average, modifier, msg_start, len(result))
C:\Users\kingS\anaconda3\envs\pytorch_gpu\lib\site-packages\sklearn\metrics\_classification.py:1308: UndefinedMetricWarning: Precision and F-score are ill-defined and being set to 0.0 in labels with no predicted samples. Use `zero_division` parameter to control this behavior.
  _warn_prf(average, modifier, msg_start, len(result))
C:\Users\kingS\anaconda3\envs\pytorch_gpu\lib\site-packages\sklearn\metrics\_classification.py:1308: UndefinedMetricWarning: Precision and F-score are ill-defined and being set to 0.0 in labels with no predicted samples. Use `zero_division` parameter to control this behavior.
  _warn_prf(average, modifier, msg_start, len(result))
# 中文字体设置
plt.rcParams['font.sans-serif'] = ['FangSong']
plt.rcParams['axes.unicode_minus'] = False

fig,ax = plt.subplots()
cm = confusion_matrix(y_test,y_pred)

df_cm = pd.DataFrame(cm,index=target1,columns=target1)
hmap = sns.heatmap(df_cm,annot=True,fmt='d')

ax.set_ylabel('True labels')
ax.set_xlabel('Predicted labels')



Text(0.5, 28.453125, 'Predicted labels')

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LmHsblvT-1639363505735)(output_43_1.png)]


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Wency(王斯-CUEB)

我不是要饭的

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值