Merge branch 'Joel-ML' of https://git.wmi.amu.edu.pl/s425077/PotatoPlan into Joel-ML

This commit is contained in:
BOTLester 2020-06-14 18:02:02 +02:00
commit ad92969137
7 changed files with 156 additions and 39 deletions

BIN
Example.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 872 KiB

BIN
Game1/Content/Example.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 872 KiB

View File

@ -14,7 +14,7 @@ class Crops
private int cropType = 0; private int cropType = 0;
private float Timer = 1; private float Timer = 1;
private int UpdateCrop; private int UpdateCrop;
private float fullTimer; private float fullTimer = 1;
private bool housePos = false; private bool housePos = false;
private Vector2 Size; private Vector2 Size;
private Random r = new Random(); private Random r = new Random();
@ -24,6 +24,7 @@ class Crops
private float tempRain; private float tempRain;
private float prevpred; private float prevpred;
private DayNightCycle Time = new DayNightCycle(); private DayNightCycle Time = new DayNightCycle();
private int previousDay = 0;
@ -244,13 +245,17 @@ class Crops
public void setCropType(int Type, CropTypes nCropType) public void setCropType(int Type, CropTypes nCropType)
{ {
if (Timer == fullTimer)
{
CropTypes temp = DataSet;
DataSet = nCropType; DataSet = nCropType;
cropType = Type; cropType = Type;
if (Status > 1)
if (Status == 3)
{ {
soilProperties.Area = r.Next(nCropType.AreaMin, nCropType.AreaMax); soilProperties.Area = r.Next(nCropType.AreaMin, nCropType.AreaMax);
if (temp != nCropType)
updateMLModel(DataSet, 1.0f);
}
} }
} }
@ -275,6 +280,7 @@ class Crops
public void setStatus(int newStatus) public void setStatus(int newStatus)
{ {
Status = newStatus; Status = newStatus;
Timer = getCropTimer();
} }
public void setOriginalStatus() public void setOriginalStatus()
@ -334,25 +340,9 @@ class Crops
public float getProductionRate(CropTypes Sample) public float getProductionRate(CropTypes Sample)
{ {
float predProd = 1.0f; float predProd = 1.0f;
if (Status > 1 && Time.nDay()) if (Status > 1 && Time.getDays() != previousDay)
{ {
bool correctSeason = false; predProd = updateMLModel(Sample, predProd);
foreach (string i in Sample.Season)
{
if (i == Time.getTimeOfYear() || i == "Whole Year")
{
correctSeason = true;
break;
}
}
if (correctSeason)
{
predProd = Game1.Sources.ML_Joel.Engine.PredictProductionwithRainfall(soilProperties, Time);
predProd = (predProd / soilProperties.Area) / 2;
}
else
predProd = 0.20f;
} }
prevpred = predProd; prevpred = predProd;
ProductionRate = 1; ProductionRate = 1;
@ -396,6 +386,30 @@ class Crops
return ProductionRate * prevpred; return ProductionRate * prevpred;
} }
public float updateMLModel(CropTypes Sample, float predProd)
{
previousDay = Time.getDays();
bool correctSeason = false;
foreach (string i in Sample.Season)
{
if (i == Time.getTimeOfYear() || i == "Whole Year")
{
correctSeason = true;
break;
}
}
if (correctSeason)
{
predProd = Game1.Sources.ML_Joel.Engine.PredictProductionwithRainfall(soilProperties, Time);
predProd = (predProd / soilProperties.Area) / 2;
}
else
predProd = 0.20f;
return predProd;
}
public float getProductionRate() public float getProductionRate()
{ {
return ProductionRate; return ProductionRate;

View File

@ -20,7 +20,7 @@ class Farm
private float[][] whiteNoise; private float[][] whiteNoise;
private float[][] perlinNoise; private float[][] perlinNoise;
private DayNightCycle Time; private DayNightCycle Time;
private float updatePerc = 0.10f; private float updatePerc = 0.01f;
private float updateProgress = 0; private float updateProgress = 0;
private float nextUpdate = 0; private float nextUpdate = 0;
private int productionUpdate = 0; private int productionUpdate = 0;
@ -141,7 +141,7 @@ class Farm
Update = 0; Update = 0;
} }
updateRainMapPosition(Size); updateRainMapPosition(Size);
if (productionUpdate == 60) if (productionUpdate == 2)
{ {
nextUpdate = updateProgress + updatePerc; nextUpdate = updateProgress + updatePerc;
for (int i = (int)(updateProgress * Size.X); i < nextUpdate * Size.X; i++) for (int i = (int)(updateProgress * Size.X); i < nextUpdate * Size.X; i++)

View File

@ -11,7 +11,7 @@ using Microsoft.ML.Trainers.LightGbm;
class MLModel class MLModel
{ {
private static MLContext mlContext = new MLContext(seed: 1); private static MLContext mlContext = new MLContext(seed: 1);
/*
private static string path = "C:/Users/Oskar/source/repos/PotatoPlanFinal/Game1/Content/ML/Fertilizer_Prediction.csv"; private static string path = "C:/Users/Oskar/source/repos/PotatoPlanFinal/Game1/Content/ML/Fertilizer_Prediction.csv";
private static string modelpath = "C:/Users/Oskar/source/repos/PotatoPlanFinal/Game1/Content/ML/MLmodel"; private static string modelpath = "C:/Users/Oskar/source/repos/PotatoPlanFinal/Game1/Content/ML/MLmodel";
private static string report = "C:/Users/Oskar/source/repos/PotatoPlanFinal/Game1/Content/ML/report"; private static string report = "C:/Users/Oskar/source/repos/PotatoPlanFinal/Game1/Content/ML/report";
@ -19,7 +19,7 @@ class MLModel
private static string pathBig = "C:/Users/Oskar/source/repos/PotatoPlanFinal/Game1/Content/ML/BigFertPredict.csv"; private static string pathBig = "C:/Users/Oskar/source/repos/PotatoPlanFinal/Game1/Content/ML/BigFertPredict.csv";
private static string modelpathBig = "C:/Users/Oskar/source/repos/PotatoPlanFinal/Game1/Content/ML/MLmodelBig"; private static string modelpathBig = "C:/Users/Oskar/source/repos/PotatoPlanFinal/Game1/Content/ML/MLmodelBig";
private static string reportBig = "C:/Users/Oskar/source/repos/PotatoPlanFinal/Game1/Content/ML/report_BigModel"; private static string reportBig = "C:/Users/Oskar/source/repos/PotatoPlanFinal/Game1/Content/ML/report_BigModel";
/* */
private static string pathBig = "C:/Users/Joel/source/repos/Oskars Repo/Game1/Content/ML/BigFertPredict.csv"; private static string pathBig = "C:/Users/Joel/source/repos/Oskars Repo/Game1/Content/ML/BigFertPredict.csv";
private static string modelpathBig = "C:/Users/Joel/source/repos/Oskars Repo/Game1/Content/ML/MLmodelBig"; private static string modelpathBig = "C:/Users/Joel/source/repos/Oskars Repo/Game1/Content/ML/MLmodelBig";
private static string reportBig = "C:/Users/Joel/source/repos/Oskars Repo/Game1/Content/ML/report_BigModel"; private static string reportBig = "C:/Users/Joel/source/repos/Oskars Repo/Game1/Content/ML/report_BigModel";
@ -27,7 +27,7 @@ class MLModel
private static string path = "C:/Users/Joel/source/repos/Oskars Repo/Game1/Content/ML/Fertilizer_Prediction.csv"; private static string path = "C:/Users/Joel/source/repos/Oskars Repo/Game1/Content/ML/Fertilizer_Prediction.csv";
private static string modelpath = "C:/Users/Joel/source/repos/Oskars Repo/Game1/Content/ML/MLmodel"; private static string modelpath = "C:/Users/Joel/source/repos/Oskars Repo/Game1/Content/ML/MLmodel";
private static string report = "C:/Users/Joel/source/repos/Oskars Repo/Game1/Content/ML/report"; private static string report = "C:/Users/Joel/source/repos/Oskars Repo/Game1/Content/ML/report";
*/
// Loading data, creatin and saving ML model for smaller dataset (100) // Loading data, creatin and saving ML model for smaller dataset (100)
public static void CreateModel() public static void CreateModel()
{ {

View File

@ -13,7 +13,7 @@ namespace Game1.Sources.ML_Joel
class Model class Model
{ {
private static MLContext mlContext = new MLContext(seed: 1); private static MLContext mlContext = new MLContext(seed: 1);
/*
private static string path = "C:/Users/Oskar/source/repos/PotatoPlanFinal/Game1/Content/ML/Rainfall.csv"; private static string path = "C:/Users/Oskar/source/repos/PotatoPlanFinal/Game1/Content/ML/Rainfall.csv";
private static string modelpath = "C:/Users/Oskar/source/repos/PotatoPlanFinal/Game1/Content/ML/MLmodel_Joel"; private static string modelpath = "C:/Users/Oskar/source/repos/PotatoPlanFinal/Game1/Content/ML/MLmodel_Joel";
private static string report = "C:/Users/Oskar/source/repos/PotatoPlanFinal/Game1/Content/ML/report_Joel"; private static string report = "C:/Users/Oskar/source/repos/PotatoPlanFinal/Game1/Content/ML/report_Joel";
@ -21,8 +21,8 @@ namespace Game1.Sources.ML_Joel
private static string path_area = "C:/Users/Oskar/source/repos/PotatoPlanFinal/Game1/Content/ML/Rainfall_area.csv"; private static string path_area = "C:/Users/Oskar/source/repos/PotatoPlanFinal/Game1/Content/ML/Rainfall_area.csv";
private static string modelpath_area = "C:/Users/Oskar/source/repos/PotatoPlanFinal/Game1/Content/ML/MLmodel_Joel_area"; private static string modelpath_area = "C:/Users/Oskar/source/repos/PotatoPlanFinal/Game1/Content/ML/MLmodel_Joel_area";
private static string report_area = "C:/Users/Oskar/source/repos/PotatoPlanFinal/Game1/Content/ML/report_Joel_area"; private static string report_area = "C:/Users/Oskar/source/repos/PotatoPlanFinal/Game1/Content/ML/report_Joel_area";
*/
/*
private static string path = "C:/Users/Joel/source/repos/Oskars Repo/Game1/Content/ML/Rainfall.csv"; private static string path = "C:/Users/Joel/source/repos/Oskars Repo/Game1/Content/ML/Rainfall.csv";
private static string modelpath = "C:/Users/Joel/source/repos/Oskars Repo/Game1/Content/ML/MLmodel_Joel"; private static string modelpath = "C:/Users/Joel/source/repos/Oskars Repo/Game1/Content/ML/MLmodel_Joel";
private static string report = "C:/Users/Joel/source/repos/Oskars Repo/Game1/Content/ML/report_Joel"; private static string report = "C:/Users/Joel/source/repos/Oskars Repo/Game1/Content/ML/report_Joel";
@ -30,7 +30,7 @@ namespace Game1.Sources.ML_Joel
private static string path_area = "C:/Users/Joel/source/repos/Oskars Repo/Game1/Content/ML/Rainfall_area.csv"; private static string path_area = "C:/Users/Joel/source/repos/Oskars Repo/Game1/Content/ML/Rainfall_area.csv";
private static string modelpath_area = "C:/Users/Joel/source/repos/Oskars Repo/Game1/Content/ML/MLmodel_Joel_area"; private static string modelpath_area = "C:/Users/Joel/source/repos/Oskars Repo/Game1/Content/ML/MLmodel_Joel_area";
private static string report_area = "C:/Users/Joel/source/repos/Oskars Repo/Game1/Content/ML/report_Joel_area"; private static string report_area = "C:/Users/Joel/source/repos/Oskars Repo/Game1/Content/ML/report_Joel_area";
*/
// Loading data, creatin and saving ML model for smaller dataset (100) // Loading data, creatin and saving ML model for smaller dataset (100)
public static void CreateModel() public static void CreateModel()
{ {

103
Joels Individual Report.md Normal file
View File

@ -0,0 +1,103 @@
Machine Learning Implementation
Introduction
I have implemented a ML to add in season, daily rainfall and area which can be cultivated into the Productivity rate of each crop. This dataset contains over 65000 entries of which we only use around 20000 as those are the only crops that are plantable for our agen and the lowest amount of entries for a single crop is 600. The daily rainfall has been added to SoilProperties in our tileset. Implementation of the needed properties into SoilProperties:
public float Rainfall;
public float prevRainfall;
public int Area;
.
.
.
//Randomize the first days rainfall and the area,
prevRainfall = r.Next(247, 3617);
Area = r.Next(1, 270000);
The dataset is said to be based on real life data. But for our our program is not able to fit the data 1 to 1 because some Crops only had an daily rainfall from 247 to 2000 but the Rainfall of that tile could still be 3617. I havent done anything to mitigate this but it doesnt result in any strange results when passing through our data into the ML Model. It would have been better for the dataset contained rainfall data from 247 to 3617. Then the yield could possibly be lower or higher as rainfall increases or decreases. We added dynamic rainfall in is therefore constricting the rain from going outside of the datasets parameters:
//Sets previous days rainfall to current days rainfall and constrict the total rainfall from going outside of the parameters
soilProperties.prevRainfall = soilProperties.Rainfall;
if (soilProperties.prevRainfall > 3616)
soilProperties.prevRainfall = 3616;
else if (soilProperties.prevRainfall < 236)
soilProperties.prevRainfall = 236;
soilProperties.Rainfall = 0;
Implementation
I have used gradient boosting decision tree algorithm due to the features.
I used Gradient Boosting Decision Tree Algorithm for this task due to many features it has.
First a csv file is loaded:
IDataView trainingDataView = mlContext.Data.LoadFromTextFile<ModelInput>(
path: path,
hasHeader: true,
separatorChar: ',',
allowQuoting: true,
allowSparse: false);
Then it is passed to next function which will train, evaluate and build a model:
- maximizing number of leaves,
- limiting maximum tree depth,
- maximizing the amount of bins per feature,
maintaining high accuracy by:
- low learning rate combine with:
- high number of iterations.
Creating pipeline for the model:
var pipeline = mlContext.Transforms
.Text.FeaturizeText("SeasonF", "Season")
.Append(mlContext.Transforms.Text.FeaturizeText("CropF", "Crop"))
.Append(mlContext.Transforms.Concatenate("Features", "SeasonF", "CropF", "Area", "Rainfall"))
.AppendCacheCheckpoint(mLContext)
.Append(mLContext.Regression.Trainers.LightGbm(options));
.Append(mlContext.Transforms.Conversion.MapKeyToValue("PredictedLabel", "PredictedLabel"));
Integration
Our tileset now has a dynamically moving overlay of clouds moving at the speed of WindSpeed and if the clouds are above at a tile we add to the total rainfall of the day. The rainfall we pass into the ML Model is the previous days rainfall and the first days rainfall is randomized.
We achieved this rainsystem by running a bitmap over our tileset, the bitmap is continues with itself so it runs seamlessly. Depending on the ransparency of each pixel on this bitmap we determine how much it is currently raining on set tile:
if (Rain >= 0.45f)
{
soilProperties.Rainfall = soilProperties.Rainfall + Rain * 4;
}
if the transparency is < 0.45 then there will be no cloud drawn and it will not be raining at all. And this is the result:
(https://git.wmi.amu.edu.pl/s425077/PotatoPlan/raw/Oskar-ML/Example.jpg)
To optimize the program we now update 10% of the columns every second or else it would freeze for seconds at a time and the ML Model is only being fed data once a day as the total rainfall is only updated once a day anyways.