AI农业防灾预测系统
背景事件
5月25日以来,河南省出现大范围持续阴雨天气,与豫南地区小麦成熟期高度重合。导致河南省内部分地区麦田积水,未收获的小麦点片倒伏、发霉,部分地区出现小麦籽粒萌动和穗发芽现象。据河南当地媒体报道,当地遭遇了10多年来最为严重的“烂场雨”天气。
目前,河南省通过抢排田间积水、加强农机调度、抓紧烘干晾晒等措施,应急抢收。为农户减少了很大的损失。但由于部分地区地势低洼,农机无法正常进入强收。导致部分农户仍然受灾严重。
方案介绍
近年来极端天气事件频发,如干旱、洪涝和高温等,这些都会对农作物的生长产生不利影响。AI可以通过大数据分析和预测天气变化,帮助农民制定更加科学的种植计划,选择适应气候变化的农作物品种,预防病虫害以及优化灌溉和施肥策略。
借助此次黑客松大赛,我们计划使用intel one AI工具包,开发一个AI农业防灾预测系统。为农户提供科学、稳定的预测指导。实现将可能出现的灾情提前上报,防患于未然。
病虫害监测
说起农作物病虫害监测,人们脑海中浮现的场景往往是植保部门测报人员手拿着小本子,站在田间,通过目测的方法,“以点代面”估测田间病虫害情况。如今,这种传统的作物病虫害诊断和监测方法已不能满足大范围精准农业生产的迫切需求。与传统监测方式相比,遥感技术作为一种监测范围广、速度快、非接触、无破坏、无污染的农作物病虫害监测技术,可实现经济、社会、生态效益的统一;且遥感信息具有覆盖面积大、探测周期短、数据丰富、现势性强等优势。
农作物病虫害一般发生在高温、高湿以及作物生长旺盛的地方,所以对病虫害的监测离不开作物长势监测和气象条件监测。
水肥一体监测
智能农业设备可以通过传感器和物联网技术收集土壤和气象数据,然后利用AI技术对数据进行分析和预测,为农民提供科学决策依据。此外,AI还可以通过优化农业管理和提高农业生产效率,降低农业对环境的影响,为实现绿色农业提供支持。
本方案将接将使用一个简化的天气数据集和土壤数据集进行预测。天气数据集包含以下特征:温度、湿度、风速和气压。土壤数据集包含酸碱度、湿度、全氮磷钾、碱解氮、速效磷、速效钾。
我们的目标是使用Scikit-learn 根据作物的周期,对于当前天气及土壤数据,以及遥感数据,对农作行为提出参考性指导建议。同时利用 Intel® Extension for Scikit-learn 进行优化,提高性能。
构建智能防灾减灾体系的关键技术
1.物联网技术
物联网技术是构建智能防灾减灾体系的重要技术支持。通过物联网技术,可以实现对农业生产全过程的实时监控和管理,包括土壤湿度、气象条件、病虫害情况等。通过对这些数据的实时监测和分析,农民可以及时掌握农业生产的进展情况,采取有效措施,降低灾害发生的可能性。
2.人工智能技术
人工智能技术是构建智能防灾减灾体系的重要辅助技术。通过人工智能技术,可以实现对农业生产的精准化管理和预测。例如,通过机器学习算法,可以对病虫害情况进行智能预测,并提供相应的防治措施。人工智能技术还可以对农业生产的各个环节进行智能化控制,提高农业生产的效率和质量。
3.遥感技术
遥感技术是构建智能防灾减灾体系的重要遥感技术。通过遥感技术,可以快速、准确地获取农业生产的相关信息,包括土壤湿度、气象条件、病虫害情况等。通过对这些信息的实时监测和分析,农民可以及时掌握农业生产的进展情况,采取有效措施,降低灾害发生的可能性。
混合模型水肥监测
1.安装 Intel Extension for Scikit-learn
Intel® Extension for Scikit-learn是一种用于加速Scikit-learn应用程序的无缝方式。它通过使用英特尔®oneAPI数据分析库(oneDAL)来实现加速。该扩展可以为Scikit-learn算法提供优化实现,从而提高这些算法的性能和效率。使用Intel® Extension for Scikit-learn可以显着提升Scikit-learn应用程序的性能,并且它还是开源的,可以免费下载和使用。
使用Intel® Extension for Scikit-learn可以实现以下功能:
加速Scikit-learn算法的运行速度,通常可以获得1-3个数量级的效率改进。
提供Scikit-learn算法的优化实现,这些算法与原始版本一致,但具有更好的性能和效率。
可以在常见的建模方法基础上,通过添加几行代码,实现性能提升。
开发前我们要确保已经安装了 Intel® Extension for Scikit-learn。可以通过以下命令安装或者在官网通过在线包安装:
pip install scikit-learn-intelex
2.对天气数据进行预测
部分代码如下
1.启用 Intel® Extension for Scikit-learn
import numpy as np
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_squared_error
from sklearnex import patch_sklearn
patch_sklearn()
# 读取天气数据
data = pd.read_csv("weather_data.csv")
划取特征和目标变量、这里划取的是温度、湿度、风速和气压。
然后进行特征缩放,使用线性回归模型进行预测
# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# 特征缩放
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)
# 使用线性回归模型进行预测
model = LinearRegression()
model.fit(X_train_scaled, y_train)
# 预测
y_pred = model.predict(X_test_scaled)
# 计算均方误差
mse = mean_squared_error(y_test, y_pred)
3.对土壤数据进行预测
实现与天气相同,但是模型使用的是随机森林回归模型。使用主成分分析(PCA)进行特征缩减 。
......
pca = PCA(n_components=3)
X_train_pca = pca.fit_transform(X_train)
X_test_pca = pca.transform(X_test)
.......
# 使用随机森林回归模型进行预测
model = RandomForestRegressor(n_estimators=100, random_state=42)
model.fit(X_train_scaled, y_train)
4.模型整合数据分析
整合天气预测数据和土壤分析数据 ,进行数据分析。使用测试集评估综合模型的性能
# 加载综合数据集
combined_data = load_combined_data()
# 训练综合模型
combined_model = LinearRegression()
combined_model.fit(combined_data, y=None)
# 使用测试集评估综合模型的性能
score = combined_model.score(combined_data, y_test)
print("Combined prediction accuracy:", score)
FCN遥感影像分类,数据解析
vgg预训练的网络结构
pretrained_net = models.vgg16_bn(pretrained=False)
pretrained_net.features[:7]
这里我们主要实现FCN 最后一层接softmax并预测 ,FCN 最后一层输出尺寸 eg: 1344 ===>即 1张 3通道的 44特征图
我们希望通过,FCN网格得到的预测分数图,变为一张可视化的图片,即网络的预测的最终结果。
1.FCN8s 网络结构代码实现
CrossEntropyLoss和NLLLoss都是用于多分类问题的损失函数,它们都基于softmax函数。
CrossEntropyLoss:这个损失函数结合了softmax和NLLLoss。在计算CrossEntropyLoss之前,模型会先通过softmax函数将输入概率分布转化为输出概率分布。然后,CrossEntropyLoss按照这个概率分布计算损失。因此,CrossEntropyLoss能够自然地处理多分类问题,并且可以直接用于训练神经网络模型。
NLLLoss:负对数似然损失函数(Negative Log Likelihood Loss)。在计算NLLLoss之前,模型也需要通过softmax函数将输入概率分布转化为输出概率分布。然后,NLLLoss根据这个概率分布和真实标签计算损失。然而,由于NLLLoss没有直接考虑标签的类别分布,它不能直接用于训练神经网络模型,通常用于评估模型的性能。
因此,CrossEntropyLoss和NLLLoss都涉及到softmax函数,区别在于它们如何使用softmax函数计算损失。另外,由于它们的性质和用途不同,选择使用哪一个损失函数取决于具体的应用场景和需求。
# Import Extension
import intel_pytorch_extension as ipex
# Automatically mix precision
ipex.enable_auto_optimization(mixed_dtype = torch.bfloat16)
class FCN8s(nn.Module):
# 定义双线性插值,作为转置卷积的初始化权重参数
def __init__(self,pretrained_net,num_classes):
super(FCN8s,self).__init__()
# (0): Conv2d(3, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
# (1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
# (2): ReLU(inplace=True)
# (3): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
# (4): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
# (5): ReLU(inplace=True)
# (6): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
# pool1 按照上述图片命名
self.pool1 = pretrained_net.features[:7]
self.pool2 = pretrained_net.features[7:14]
self.pool3 = pretrained_net.features[14:24]
self.pool4 = pretrained_net.features[24:34]
self.pool5 = pretrained_net.features[34:]
self.relu = nn.ReLU(inplace=True)
self.deconv1 = nn.ConvTranspose2d(512, 512, kernel_size=3, stride=2, padding=1, dilation=1, output_padding=1)
self.bn1 = nn.BatchNorm2d(512)
self.deconv2 = nn.ConvTranspose2d(512, 256, kernel_size=3, stride=2, padding=1, dilation=1, output_padding=1)
self.bn2 = nn.BatchNorm2d(256)
self.deconv3 = nn.ConvTranspose2d(256, 128, kernel_size=3, stride=2, padding=1, dilation=1, output_padding=1)
self.bn3 = nn.BatchNorm2d(128)
self.deconv4 = nn.ConvTranspose2d(128, 64, kernel_size=3, stride=2, padding=1, dilation=1, output_padding=1)
self.bn4 = nn.BatchNorm2d(64)
self.deconv5 = nn.ConvTranspose2d(64, 32, kernel_size=3, stride=2, padding=1, dilation=1, output_padding=1)
self.bn5 = nn.BatchNorm2d(32)
self.classifier = nn.Conv2d(32, num_classes, kernel_size=1)
def forward(self,x): # x = 352, 480,3 = height, width, channels
# s1第一个下采样块的输出特征图
# x为输入图像
# layer1 为Vgg网络下,第一个下采样块和之前的结构
s1 = self.pool1(x) # >>> s1 = 176, 240,64 # 1/2
s2 = self.pool2(s1) # >>> s2 = 88, 120, 128 # 1/4
s3 = self.pool3(s2) # >>> s3 = 44, 60, 256 # 1/8
s4 = self.pool4(s3) # >>> s4 = 22, 30, 512 # 1/16
s5 = self.pool5(s4) # >>> s5 = 11, 15, 512 # 1/32 通道数增加到512,到700左右就行了,不闭增加过多
# relu 用来防止梯度消失
# bn 层用来,使数据保持高斯分布
# bn层 的里面是relu层,外面是转置卷积层, relu内部接转置卷积结果
scores = self.relu(self.deconv1(s5)) # h,w,n = 22, 30, 512 1/16
scores = self.bn1(scores + s4) # h,w,n = 22, 30, 512 1/16
scores = self.relu(self.deconv2(scores)) # h,w,n = 44 , 60, 256 1/8
scores = self.bn2(scores + s3)
scores = self.bn3(self.relu(self.deconv3(scores))) # h,w,n = 88, 120, 128 1/4
scores = self.bn4(self.relu(self.deconv4(scores))) # h,w,n = 176, 240, 64 1/2
scores = self.bn5(self.relu(self.deconv5(scores))) # h,w,n = 352, 480, 32 1/1
return self.classifier(scores) # h,w,n= 352, 480, 5 1/1
2. 数据集导入
def __init__(self, img_path : str, label_path : str, labelUtils : LabelUtil):
super(UserDataset,self).__init__()
# 初始化图片和标签全路径,数组
self.imgslist = [os.path.join(img_path,item) for item in os.listdir(img_path)]
self.labelslist = [os.path.join(label_path,item) for item in os.listdir(label_path)]
self.transforms = transforms.Compose([
transforms.ToTensor(),
transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
])
self.labelUtils = labelUtils
# 路径按名字,排个序
self.imgslist.sort()
self.labelslist.sort()
3.训练
def trainNet(self):
for epoch in range(30):
print('epoch = '+str(epoch)+', loss = '+str(self.loss))
if epoch % 10 == 0 and epoch != 0:
for group in self.optimizer.param_groups:
group['lr'] *= 0.5
self.fcn.train() # 设置为训练过程。此时网络 的 参数能够进行参数学习
for i, sample in tqdm(enumerate(self.dataLoader)):
# Variable为tensor数据构建计算图,便于网络的运算 https://www.cnblogs.com/czz0508/p/10333359.html
imgdata, imglabel = Variable(sample['img']).to(ipex.DEVICE), Variable(sample['label'].long()).to(ipex.DEVICE)
self.optimizer.zero_grad() # 梯度清0
netOutput = self.fcn(imgdata) # 将训练图片 送入网络
loss = self.calLoss(netOutput , imglabel) # 计算损失, label 和 网络输出的预测的结果进行对比,计算loss
loss.backward() # 误差反向传播
self.optimizer.step() # 用优化器去更新权重参数
self.loss += loss.item() # 训练损失 记录
t.save(self.fcn.state_dict(), self.modelsavepath)
print('*'*10,'train end')
完成单张图预测并将预测图覆盖到原图上。
这里我们没找到合适精度的图,使用了农田区块作为代替。
后续我们将遥感数据整合到上述模型的csv数据集中,进行混合训练和微调,最终输出未来三天内是否需要施肥、浇水、抢收。
总结
我们使用了Intel® Extension for Scikit-learn 实现了一个农作物指导的简易模型,并测试了Scikit-learn与Intel® Extension for Scikit-learn的训练速度,平均回归测试,提高了22%的性能。同时使用intel_pytorch_extension实现了一个遥感影像数据解析功能。通过这次比赛,也是学习了解了intel 的oneAPi库。收获很多。