برای مشاهده و کار کردن با ظاهر برو روی لینک کلیک کنید
ویدیو زیر نحوه کار با سایت را نشان می دهد
این پروژه از دو بخش تشکبل شده است
- فایل
main.dart
- فایل
hmm.dart
این فایل مسئول بخش ظاهر این پروژه میباشد
این فایل مسئول بخش محاسباتی پروژه می باشد. مدل و تابع hmmCalc
با دریافت ارایه ای کلمات موجود در لیست کلمات قبول درصد احتمال هر حالت محاسبه میکند.
برای محاسبه ابتدا باید مدل آن مشخص شود. شکل زیر مدل و احتمال آن را نشان می دهد
این کلاس مسثولیت نگهداری اطلاعات مدل را دارد.خطوط زیر برای تعریف کلمات و حالات و وزن این مدل تعریف شدند
static const List<String> kWORDS = [
"boat",
"man",
"old",
"rows",
"the",
".",
];
final Map<String, List<double>> outputProb = {
kWORDS[0]: [0.2, 0.0, 0.2, 0.0],
kWORDS[1]: [0.2, 0.2, 0.2, 0.0],
kWORDS[2]: [0.2, 0.0, 0.2, 0.0],
kWORDS[3]: [0.1, 0.8, 0.1, 0.0],
kWORDS[4]: [0.3, 0.0, 0.3, 0.0],
kWORDS[5]: [0.0, 0.0, 0.0, 1.0],
};
static const stateNumber = {
"subject": 0,
"verb": 1,
"object": 2,
"end": 3,
};
static const stateName = [
"subject",
"verb",
"object",
"end",
];
final Map<String, List<Map<String, Object>>> stateOutProb = {
stateName[0]: [
{"name": stateName[0], "prob": 0.5},
{"name": stateName[1], "prob": 0.5},
],
stateName[1]: [
{"name": stateName[2], "prob": 0.7},
{"name": stateName[3], "prob": 0.3},
],
stateName[2]: [
{"name": stateName[2], "prob": 0.5},
{"name": stateName[3], "prob": 0.5},
],
stateName[3]: [
{"name": stateName[3], "prob": 1.0},
],
};
final Map<String, Map<String, double>> stateWordProb = {
stateName[0]: {
kWORDS[0]: 0.2,
kWORDS[1]: 0.2,
kWORDS[2]: 0.2,
kWORDS[3]: 0.1,
kWORDS[4]: 0.3,
kWORDS[5]: 0.0,
},
stateName[1]: {
kWORDS[0]: 0.0,
kWORDS[1]: 0.2,
kWORDS[2]: 0.0,
kWORDS[3]: 0.8,
kWORDS[4]: 0.0,
kWORDS[5]: 0.0,
},
stateName[2]: {
kWORDS[0]: 0.2,
kWORDS[1]: 0.2,
kWORDS[2]: 0.2,
kWORDS[3]: 0.1,
kWORDS[4]: 0.3,
kWORDS[5]: 0.0,
},
stateName[3]: {
kWORDS[0]: 0.0,
kWORDS[1]: 0.0,
kWORDS[2]: 0.0,
kWORDS[3]: 0.0,
kWORDS[4]: 0.0,
kWORDS[5]: 1.0,
},
};
double getProbWordInState({
required String word,
required String state,
}) {
final getStateNumber = stateNumber[state]!;
return outputProb[word]![getStateNumber];
}
List<Map<String, Object>> findPossibleNextState({
required String prevState,
required String word,
}) {
final nextStateProp = stateOutProb[prevState]!;
final List<Map<String, Object>> data = [];
for (var element in nextStateProp) {
final nameOfState = element["name"];
final probOfState = element["prob"] as double;
final indexOfState = stateWordProb[nameOfState]!;
final wordInStateProb = indexOfState[word]!;
if (wordInStateProb * probOfState != 0) {
data.add({
"state": element["name"] as String,
"prob": wordInStateProb * probOfState,
});
}
}
return data;
}
class Path {
final List<String> states;
final double prob;
Path({
required this.states,
required this.prob,
});
get currentState => states.last;
Path copyWith({
required String newState,
required double newProb,
}) {
return Path(
states: [...states, newState],
prob: prob * newProb,
);
}
}
در نهایت می توان به تابع hmmCalc
اشاره کرد که وظیفه محاسبه حالت ها و احتمال حالات را دارد برای سادگی می توان آن را به ۳ بخش تقسیم کرد
- چک کردن طول کلمات و بازگشت در صورت خالی بودن لیست همچنین چک کردن این که
"."
در اول جمله نباشد زیرا جمله نمی تواند با"."
شروع شود
if (myWords.isEmpty) {
return [];
}
if (myWords.first == ".") {
return [];
}
- محاسبه احتمال اولین کلمه (زیر این کلمه باید در حالت
"subject"
شروع شود محاسبه آن با بقیه حالات متفاوت است)
final hmm = HMM();
List<Path> output = [];
output.add(
Path(
states: ["subject"],
prob: hmm.getProbWordInState(
word: myWords[0],
state: "subject",
),
),
);
3.در بخش پایانی از دومین کلمه لیست کلمات شروع می کنیم سپس این کلمات را به این صورت حساب می کنیم که ابتدا از مسیر های موجود اخرین حالت را پیدا می کنیم سپس محاسبه می کنیم که آیا با کلمه موجود و حالتی که در آن هستیم می توان به حالت جدیدی راه پیدا کرد یا نه .اگر احتمال آن وجود داشت این مسبر و حالت را اضافه می کنیم همچنین احتمال آن را نیز با احتمال های موجود ضرب می کنیم. این کار را آنقدر ادامه میدهیم تا کلمات به پایان برسند یا در مرحله تعداد مسیر ها صفر شود که نشان دهنده این است که احتمال این حالت وجود ندارد
for (var i = 1; i < myWords.length; i++) {
List<Path> tempOutput = [];
if (output.isEmpty) {
break;
}
for (var item in output) {
final x = hmm.findPossibleNextState(
prevState: item.currentState, word: myWords[i]);
for (var element in x) {
tempOutput.add(
item.copyWith(
newState: element["state"] as String,
newProb: element["prob"] as double,
),
);
}
}
output.clear();
output.addAll(tempOutput);
}
return output;
}
برای این کار ابتدا hmmm
محاسبه می کنیم
سپس با از آن جا که احتمال هر مسیر محاسبه شده است با یکبار پیمایش مقدار مجموع و بیشترین محاسبه می شود.
final data = hmmCalc(wordList);
// این متغیر مقدار احتمال بهترین مسبر را نگهداری میکنید
double maxProb = 0;
// این متغیر مجموع احتمال این مسبر را نگهداری میکنید
double sumProb = 0;
for (var i = 0; i < data.length; i++) {
maxProb = max(maxProb, data[i].prob);
sumProb += data[i].prob;
}