rufatronics commited on
Commit
12aa8ef
·
verified ·
1 Parent(s): 918159d

FarmBot v1 — model + honest benchmark results

Browse files
README.md ADDED
@@ -0,0 +1,84 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ language: en
3
+ license: mit
4
+ base_model: HuggingFaceTB/SmolLM2-135M-Instruct
5
+ tags:
6
+ - agriculture
7
+ - crop-disease
8
+ - africa
9
+ - farmbot
10
+ - lora
11
+ - int4
12
+ ---
13
+
14
+ # FarmBot — SmolLM2-135M (INT4, LoRA Finetuned)
15
+
16
+ A LoRA finetune of SmolLM2-135M-Instruct for crop disease assistance, covering 9 crops
17
+ common in West/Central Africa. Quantized to INT4 (~111MB) for low-resource deployment.
18
+ Built for the USAII Global AI Hackathon 2026.
19
+
20
+ ## Crops Covered
21
+ Cassava, Cocoa, Cowpea, Maize, Groundnut, Mango, Plantain, Rice, Tomato
22
+
23
+ ## Benchmark Results (15-question held-out test, keyword-match scoring)
24
+
25
+ | Bucket | Score |
26
+ |---|---|
27
+ | Overall | 7/15 (46.7%) |
28
+ | Crop knowledge | 6/9 (67%) |
29
+ | Greetings | 1/2 (50%) |
30
+ | Out-of-scope | 0/4 (0%) |
31
+
32
+ See `benchmark_results.json` for full per-question results.
33
+
34
+ This is not a polished production model. Crop-knowledge answers are generally accurate
35
+ and on-topic (correctly identifies fall armyworm, cassava mosaic, black pod disease, bunchy
36
+ top, rice blast, cowpea aphids with reasonable treatment advice). Out-of-scope detection is
37
+ weak in raw model output — the model often starts the correct decline phrase but drifts into
38
+ unrelated crop advice instead of stopping. Greetings handling is inconsistent.
39
+
40
+ ## Known Limitations
41
+
42
+ - Out-of-scope detection fails most of the time in raw model output — **a regex pre-filter
43
+ at the application layer is required** before deploying this model to reliably handle
44
+ off-topic questions (sports, prices, politics, human/animal health, etc.)
45
+ - Responses can ramble past the useful answer and drift off-topic toward the end
46
+ - 135M parameters — limited reasoning, trained narrowly on 9 crops only, will not generalize
47
+ to crops or diseases outside its training data
48
+ - Should be treated as an early-stage assistive tool, not a substitute for an agricultural
49
+ extension officer
50
+
51
+ ## Training
52
+
53
+ - Base: HuggingFaceTB/SmolLM2-135M-Instruct
54
+ - LoRA: r=16, alpha=32, dropout=0.05, targeting q/k/v/o projections (~1.84M trainable params)
55
+ - Data: ~95,000 quality-filtered examples (deduplicated, length-bounded, repetition-checked),
56
+ sampled from a larger 365k+ synthetic Q&A dataset generated via Mistral API
57
+ - Hardware: Kaggle 2x T4
58
+ - Quantization: INT4 nf4 with double quant
59
+
60
+ ## Recommended Inference Settings
61
+
62
+ ```python
63
+ temperature=0.3, top_k=20, repetition_penalty=1.2
64
+ max_new_tokens=120, min_new_tokens=15
65
+ eos_token_id=tokenizer.convert_tokens_to_ids('<|im_end|>')
66
+ ```
67
+
68
+ ## Usage
69
+
70
+ ```python
71
+ from transformers import AutoTokenizer, AutoModelForCausalLM
72
+ tokenizer = AutoTokenizer.from_pretrained("rufatronics/farmbot-crop-assistant")
73
+ model = AutoModelForCausalLM.from_pretrained("rufatronics/farmbot-crop-assistant", device_map="auto")
74
+
75
+ prompt = "<|im_start|>user\nmy maize leaves have holes<|im_end|>\n<|im_start|>assistant\n"
76
+ inputs = tokenizer(prompt, return_tensors="pt").to(model.device)
77
+ out = model.generate(
78
+ **inputs, max_new_tokens=120, min_new_tokens=15,
79
+ temperature=0.3, top_k=20, do_sample=True, repetition_penalty=1.2,
80
+ pad_token_id=tokenizer.eos_token_id,
81
+ eos_token_id=tokenizer.convert_tokens_to_ids('<|im_end|>'),
82
+ )
83
+ print(tokenizer.decode(out[0][inputs['input_ids'].shape[1]:], skip_special_tokens=True))
84
+ ```
benchmark_results.json ADDED
@@ -0,0 +1,83 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "overall": "7/15 (46.7%)",
3
+ "crop_knowledge": "6/9 (67%)",
4
+ "greetings": "1/2 (50%)",
5
+ "out_of_scope": "0/4 (0%)",
6
+ "details": [
7
+ {
8
+ "passed": true,
9
+ "score": 0.6666666666666666,
10
+ "bucket": "crop_knowledge"
11
+ },
12
+ {
13
+ "passed": true,
14
+ "score": 0.6666666666666666,
15
+ "bucket": "crop_knowledge"
16
+ },
17
+ {
18
+ "passed": true,
19
+ "score": 0.6666666666666666,
20
+ "bucket": "crop_knowledge"
21
+ },
22
+ {
23
+ "passed": true,
24
+ "score": 1.0,
25
+ "bucket": "crop_knowledge"
26
+ },
27
+ {
28
+ "passed": false,
29
+ "score": 0.3333333333333333,
30
+ "bucket": "crop_knowledge"
31
+ },
32
+ {
33
+ "passed": false,
34
+ "score": 0.0,
35
+ "bucket": "crop_knowledge"
36
+ },
37
+ {
38
+ "passed": true,
39
+ "score": 1.0,
40
+ "bucket": "crop_knowledge"
41
+ },
42
+ {
43
+ "passed": true,
44
+ "score": 1.0,
45
+ "bucket": "crop_knowledge"
46
+ },
47
+ {
48
+ "passed": false,
49
+ "score": 0.0,
50
+ "bucket": "crop_knowledge"
51
+ },
52
+ {
53
+ "passed": true,
54
+ "score": 1.0,
55
+ "bucket": "greetings"
56
+ },
57
+ {
58
+ "passed": false,
59
+ "score": 0.3333333333333333,
60
+ "bucket": "greetings"
61
+ },
62
+ {
63
+ "passed": false,
64
+ "score": 0.3333333333333333,
65
+ "bucket": "out_of_scope"
66
+ },
67
+ {
68
+ "passed": false,
69
+ "score": 0.3333333333333333,
70
+ "bucket": "out_of_scope"
71
+ },
72
+ {
73
+ "passed": false,
74
+ "score": 0.0,
75
+ "bucket": "out_of_scope"
76
+ },
77
+ {
78
+ "passed": false,
79
+ "score": 0.3333333333333333,
80
+ "bucket": "out_of_scope"
81
+ }
82
+ ]
83
+ }
config.json ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "_name_or_path": "/kaggle/working/farmbot_smol",
3
+ "architectures": [
4
+ "LlamaForCausalLM"
5
+ ],
6
+ "attention_bias": false,
7
+ "attention_dropout": 0.0,
8
+ "bos_token_id": 1,
9
+ "eos_token_id": 2,
10
+ "head_dim": 64,
11
+ "hidden_act": "silu",
12
+ "hidden_size": 576,
13
+ "initializer_range": 0.041666666666666664,
14
+ "intermediate_size": 1536,
15
+ "is_llama_config": true,
16
+ "max_position_embeddings": 8192,
17
+ "mlp_bias": false,
18
+ "model_type": "llama",
19
+ "num_attention_heads": 9,
20
+ "num_hidden_layers": 30,
21
+ "num_key_value_heads": 3,
22
+ "pad_token_id": 2,
23
+ "pretraining_tp": 1,
24
+ "quantization_config": {
25
+ "_load_in_4bit": true,
26
+ "_load_in_8bit": false,
27
+ "bnb_4bit_compute_dtype": "float16",
28
+ "bnb_4bit_quant_storage": "uint8",
29
+ "bnb_4bit_quant_type": "nf4",
30
+ "bnb_4bit_use_double_quant": true,
31
+ "llm_int8_enable_fp32_cpu_offload": false,
32
+ "llm_int8_has_fp16_weight": false,
33
+ "llm_int8_skip_modules": null,
34
+ "llm_int8_threshold": 6.0,
35
+ "load_in_4bit": true,
36
+ "load_in_8bit": false,
37
+ "quant_method": "bitsandbytes"
38
+ },
39
+ "rms_norm_eps": 1e-05,
40
+ "rope_interleaved": false,
41
+ "rope_scaling": null,
42
+ "rope_theta": 100000,
43
+ "tie_word_embeddings": true,
44
+ "torch_dtype": "float16",
45
+ "transformers.js_config": {
46
+ "kv_cache_dtype": {
47
+ "fp16": "float16",
48
+ "q4f16": "float16"
49
+ }
50
+ },
51
+ "transformers_version": "4.46.3",
52
+ "use_cache": false,
53
+ "vocab_size": 49152
54
+ }
generation_config.json ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ {
2
+ "_from_model_config": true,
3
+ "bos_token_id": 1,
4
+ "eos_token_id": 2,
5
+ "pad_token_id": 2,
6
+ "transformers_version": "4.46.3"
7
+ }
merges.txt ADDED
The diff for this file is too large to render. See raw diff
 
model.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:3865c97294f848b9e1b3856be83a17ca00bcf3b59ccbf49906103e6f58e71209
3
+ size 111879472
special_tokens_map.json ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "additional_special_tokens": [
3
+ "<|im_start|>",
4
+ "<|im_end|>"
5
+ ],
6
+ "bos_token": {
7
+ "content": "<|im_start|>",
8
+ "lstrip": false,
9
+ "normalized": false,
10
+ "rstrip": false,
11
+ "single_word": false
12
+ },
13
+ "eos_token": {
14
+ "content": "<|im_end|>",
15
+ "lstrip": false,
16
+ "normalized": false,
17
+ "rstrip": false,
18
+ "single_word": false
19
+ },
20
+ "pad_token": {
21
+ "content": "<|im_end|>",
22
+ "lstrip": false,
23
+ "normalized": false,
24
+ "rstrip": false,
25
+ "single_word": false
26
+ },
27
+ "unk_token": {
28
+ "content": "<|endoftext|>",
29
+ "lstrip": false,
30
+ "normalized": false,
31
+ "rstrip": false,
32
+ "single_word": false
33
+ }
34
+ }
tokenizer.json ADDED
The diff for this file is too large to render. See raw diff
 
tokenizer_config.json ADDED
@@ -0,0 +1,158 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "add_prefix_space": false,
3
+ "added_tokens_decoder": {
4
+ "0": {
5
+ "content": "<|endoftext|>",
6
+ "lstrip": false,
7
+ "normalized": false,
8
+ "rstrip": false,
9
+ "single_word": false,
10
+ "special": true
11
+ },
12
+ "1": {
13
+ "content": "<|im_start|>",
14
+ "lstrip": false,
15
+ "normalized": false,
16
+ "rstrip": false,
17
+ "single_word": false,
18
+ "special": true
19
+ },
20
+ "2": {
21
+ "content": "<|im_end|>",
22
+ "lstrip": false,
23
+ "normalized": false,
24
+ "rstrip": false,
25
+ "single_word": false,
26
+ "special": true
27
+ },
28
+ "3": {
29
+ "content": "<repo_name>",
30
+ "lstrip": false,
31
+ "normalized": false,
32
+ "rstrip": false,
33
+ "single_word": false,
34
+ "special": true
35
+ },
36
+ "4": {
37
+ "content": "<reponame>",
38
+ "lstrip": false,
39
+ "normalized": false,
40
+ "rstrip": false,
41
+ "single_word": false,
42
+ "special": true
43
+ },
44
+ "5": {
45
+ "content": "<file_sep>",
46
+ "lstrip": false,
47
+ "normalized": false,
48
+ "rstrip": false,
49
+ "single_word": false,
50
+ "special": true
51
+ },
52
+ "6": {
53
+ "content": "<filename>",
54
+ "lstrip": false,
55
+ "normalized": false,
56
+ "rstrip": false,
57
+ "single_word": false,
58
+ "special": true
59
+ },
60
+ "7": {
61
+ "content": "<gh_stars>",
62
+ "lstrip": false,
63
+ "normalized": false,
64
+ "rstrip": false,
65
+ "single_word": false,
66
+ "special": true
67
+ },
68
+ "8": {
69
+ "content": "<issue_start>",
70
+ "lstrip": false,
71
+ "normalized": false,
72
+ "rstrip": false,
73
+ "single_word": false,
74
+ "special": true
75
+ },
76
+ "9": {
77
+ "content": "<issue_comment>",
78
+ "lstrip": false,
79
+ "normalized": false,
80
+ "rstrip": false,
81
+ "single_word": false,
82
+ "special": true
83
+ },
84
+ "10": {
85
+ "content": "<issue_closed>",
86
+ "lstrip": false,
87
+ "normalized": false,
88
+ "rstrip": false,
89
+ "single_word": false,
90
+ "special": true
91
+ },
92
+ "11": {
93
+ "content": "<jupyter_start>",
94
+ "lstrip": false,
95
+ "normalized": false,
96
+ "rstrip": false,
97
+ "single_word": false,
98
+ "special": true
99
+ },
100
+ "12": {
101
+ "content": "<jupyter_text>",
102
+ "lstrip": false,
103
+ "normalized": false,
104
+ "rstrip": false,
105
+ "single_word": false,
106
+ "special": true
107
+ },
108
+ "13": {
109
+ "content": "<jupyter_code>",
110
+ "lstrip": false,
111
+ "normalized": false,
112
+ "rstrip": false,
113
+ "single_word": false,
114
+ "special": true
115
+ },
116
+ "14": {
117
+ "content": "<jupyter_output>",
118
+ "lstrip": false,
119
+ "normalized": false,
120
+ "rstrip": false,
121
+ "single_word": false,
122
+ "special": true
123
+ },
124
+ "15": {
125
+ "content": "<jupyter_script>",
126
+ "lstrip": false,
127
+ "normalized": false,
128
+ "rstrip": false,
129
+ "single_word": false,
130
+ "special": true
131
+ },
132
+ "16": {
133
+ "content": "<empty_output>",
134
+ "lstrip": false,
135
+ "normalized": false,
136
+ "rstrip": false,
137
+ "single_word": false,
138
+ "special": true
139
+ }
140
+ },
141
+ "additional_special_tokens": [
142
+ "<|im_start|>",
143
+ "<|im_end|>"
144
+ ],
145
+ "bos_token": "<|im_start|>",
146
+ "chat_template": "{% for message in messages %}{% if loop.first and messages[0]['role'] != 'system' %}{{ '<|im_start|>system\nYou are a helpful AI assistant named SmolLM, trained by Hugging Face<|im_end|>\n' }}{% endif %}{{'<|im_start|>' + message['role'] + '\n' + message['content'] + '<|im_end|>' + '\n'}}{% endfor %}{% if add_generation_prompt %}{{ '<|im_start|>assistant\n' }}{% endif %}",
147
+ "clean_up_tokenization_spaces": false,
148
+ "eos_token": "<|im_end|>",
149
+ "max_length": 1024,
150
+ "model_max_length": 8192,
151
+ "pad_token": "<|im_end|>",
152
+ "stride": 0,
153
+ "tokenizer_class": "GPT2Tokenizer",
154
+ "truncation_side": "right",
155
+ "truncation_strategy": "longest_first",
156
+ "unk_token": "<|endoftext|>",
157
+ "vocab_size": 49152
158
+ }
vocab.json ADDED
The diff for this file is too large to render. See raw diff