File size: 19,880 Bytes
d55507f
 
00eec42
 
 
 
 
 
5189249
1605aa8
d55507f
 
 
 
 
 
 
0676beb
d55507f
 
 
 
 
5189249
 
 
 
d55507f
99971cc
 
 
064bc07
5189249
d55507f
 
 
5189249
 
d55507f
 
 
 
 
 
 
 
 
064bc07
d55507f
 
 
 
 
064bc07
d55507f
76f0f38
d55507f
 
 
76f0f38
d55507f
 
 
 
 
1fb5760
d55507f
4215c27
 
 
 
 
 
 
 
 
 
 
 
 
99971cc
4215c27
99971cc
4215c27
99971cc
4215c27
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
99971cc
4215c27
99971cc
 
 
 
 
 
 
 
4215c27
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
99971cc
4215c27
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
99971cc
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
d55507f
 
 
 
 
 
d183a1d
d55507f
 
 
 
d183a1d
d55507f
d183a1d
d55507f
a4a7f76
d55507f
a4a7f76
d55507f
a4a7f76
d55507f
a4a7f76
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
d55507f
 
 
 
 
 
 
 
 
 
 
 
99971cc
d55507f
 
 
 
 
99971cc
 
 
 
 
d55507f
 
 
99971cc
d55507f
99971cc
 
 
d55507f
99971cc
 
 
 
 
 
 
d55507f
99971cc
d55507f
99971cc
d55507f
99971cc
d55507f
99971cc
d55507f
 
 
1fb5760
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
---
library_name: transformers
datasets:
- glaiveai/glaive-code-assistant
language:
- en
base_model:
- mistralai/Mistral-7B-v0.1
license: apache-2.0
pipeline_tag: text-generation
---

# Model Card for Model ID

<!-- Provide a quick summary of what the model is/does. -->


## Model Summary

### Model Description

<!-- Provide a longer summary of what this model is. -->

- **Developed by:** Alden Swain
- **Model type:** Text Generation
- **Language(s) (NLP):** English
- **License:** Apache 2.0

The goal of this model is to improve the quality and efficiency of code generation from natural language prompts, particularly for Python, since this is the programming language I use most often. Many LLMs produce code that is outdated, inefficient, and bugged. Creating a custom LLM that is able to produce efficient and quality code allows the user to reduce the amount of time it takes to write code and more quickly troubleshoot bugged code. Current models may inadvertently introduce vulnerabilities or generate code that does not adhere to current norms due to the training code data occasionally lacking the safety or output aligned with human coding preferences ([Jiang et al., 2024](https://arxiv.org/html/2406.00515v1)). Additionally, current models are frequently trained on large datasets that encompass a wide range of programming languages, giving the model a roughly equal amount of training time on many languages, which may affect performance on more popular languages ([Jiang et al., 2024](https://arxiv.org/html/2406.00515v1)).

To combat this, I selected a model with 7 billion parameters that had a relatively strong performance at baseline on solving code tasks and trained the model on a large code generation dataset (~136,000 rows) that was ~60% Python code. I utilized a Program of Thought (PoT) prompting approach and LoRA training method to create an updated model. Finally, I compared the benchmark performances of MBPP, HumanEval, and MMLU on the updated model to the baseline model. The updated model had little improvement from the base model. For the tested benchmarks, MBPP rose from 37.6% to 40.2% on the first pass, and HumanEval first-pass accuracy dropped from 0.6% to 0%; however, the code appeared to have better format than the base model, and MMLU stayed about the same, with 59.6% at baseline and 59.1% after training.

### Model Sources

<!-- Provide the basic links for the model. -->

- **Repository:** [mistralai/Mistral-7B-v0.1](https://huggingface.co./mistralai/Mistral-7B-v0.1}{mistralai/Mistral-7B-v0.1)
- **Paper:** [Mistral-7B](https://arxiv.org/abs/2310.06825)

## Uses

<!-- Address questions around how the model is intended to be used, including the foreseeable users of the model and those affected by the model. -->

### Direct Use

<!-- This section is for the model use without fine-tuning or plugging into a larger ecosystem/app. -->

This model is designed to generate quality and efficient code in any programming language, but particularly for Python, given a natural language prompt. It can provide troubleshooting for bugged or broken code that is able to provide feedback on why the initial code was faulty and how the code was improved and fixed.

### Out-of-Scope Use

<!-- This section addresses misuse, malicious use, and uses that the model will not work well for. -->

This mode is not specifically designed for any other type of task. However, the model appears to still contain roughly the same generalizability as the base model. Users should consider the common limitations of language models as they select use cases and evaluate and mitigate for accuracy, safety, and fairness before using them within a specific downstream use case, particularly if being used in high-risk scenarios.

## Risks and Limitations

<!-- This section is meant to convey both technical and sociotechnical limitations. -->

The model was trained on a dataset that is predominantly Python code; therefore, asking for code in another language may not be as efficient or high quality as the user would like. The model may still generate incorrect or outdated responses given that new libraries and practices are continuously being developed and updated. The model performance may be negatively affected by open-ended or highly complex tasks, and model performance can be influenced by the amount of context provided. Providing the model with ambiguous prompts can lead to incoherent or inaccurate responses. LLMs may struggle to grasp subtle nuances, sarcasm, or figurative language. LLMs rely on statistical patterns in language and may lack the ability to apply common sense reasoning in certain situations.

### Recommendations

<!-- This section is meant to convey recommendations with respect to the bias, risk, and technical limitations. -->

Users (both direct and downstream) should be made aware of the risks and limitations of the model. Please read the above section before using this model.

## How to Get Started with the Model

Use the code below to get started with the model.

```python
from transformers import AutoTokenizer, AutoModelForCausalLM

tokenizer = AutoTokenizer.from_pretrained('mistralai/Mistral-7B-v0.1')
model = AutoModelForCausalLM.from_pretrained('aswain4/custom_coding_LLM', device_map='auto', torch_dtype=torch.bfloat16)
```

### Input Formats

Simply ask the model a question as a string and it will yield quality output. Formatting the prompt similarly to the training data will yield a more detailed explanation of the generated code. This means creating the prompt in a Program of Thought (PoT) technique.

Question only prompt:
```python
prompt = "Write a Python function to check if a number is a palindrome."

input_ids = tokenizer(prompt, return_tensors="pt").to(model.device)

#generate text
outputs = model.generate(
    **input_ids,
    max_new_tokens=300,
    temperature=0.7,
    top_p=0.95,
    do_sample=True,
    pad_token_id=tokenizer.pad_token_id
)

#decode and print
generated_text = tokenizer.decode(outputs[0], skip_special_tokens=True)
print(generated_text)
```

PoT prompt:
```python
prompt = (
    "Instruct: Plan:\n"
    "1. Analyze the following question: \"Write a Python function to check if a number is a palindrome.\"\n"
    "2. Think step by step and plan a clear, efficient solution before writing code.\n"
    "3. Consider any necessary programming constructs or tools.\n"
    "4. Explain your approach, then write well-organized and well-documented code with in-line comments.\n\n"
    "Response:"
)

input_ids = tokenizer(prompt, return_tensors="pt").to(model.device)

#generate text
outputs = model.generate(
    **input_ids,
    max_new_tokens=300,
    temperature=0.7,
    top_p=0.95,
    do_sample=True,
    pad_token_id=tokenizer.pad_token_id
)

#decode and print
generated_text = tokenizer.decode(outputs[0], skip_special_tokens=True)
print(generated_text)
```

### Expected Outputs

If the question-only prompting approach is used, the output is expected to yield the generated code followed by an explanation of what is happening in the code. If the PoT prompting approach is used, users should expect the output to yield a response stating it can perform the task, followed by the generated code, and then an explanation of what is happening in the code.

Question only output:
```text
def is_palindrome(n):
    # convert the number to string
    n = str(n)

    # check if the string is equal to its reverse
    if n == n[::-1]:
        return True
    else:
        return False


print(is_palindrome(12321))


# Output:
# True


# Explanation:
# The function is_palindrome takes a number as input and converts it to a string.
# It then checks if the string is equal to its reverse.
# If the string is equal to its reverse, the function returns True, indicating that the number is a palindrome.
# Otherwise, it returns False.
# In the given example, the number 12321 is a palindrome, so the function returns True.
```

PoT output:
```text
Sure! Here's an example of a Python function that checks if a number is a palindrome:

def is_palindrome(num):
    str_num = str(num)
    if str_num == str_num[::-1]:
        return True
    else:
        return False

num = 12321
result = is_palindrome(num)
print(result)

The function `is_palindrome` takes a number as input and converts it into a string using the `str()` function. It then checks if the string is equal to its reversed version (`str_num[::-1]`). If they are equal, it means the number is a palindrome and the function returns `True`. Otherwise, it returns `False`.

In the example code, we test the function with the number `12321`. The function call `is_palindrome(num)` returns `True` because `12321` is a palindrome. Finally, the result is printed to the console.

I hope this helps! Let me know if you have any further questions.
```

## Training Details

### Training Data

<!-- This should link to a Dataset Card, perhaps with a short stub of information on what the training data is all about as well as documentation related to data pre-processing or additional filtering. -->

The base model was trained on the Glaive code assistant dataset from Glaive AI. This dataset contains ~140,000 code problems and solutions. The problems are formatted in a natural language process, such as you would expect a human user to query. Approximately 60% of the data uses the Python language. The dataset only contains a test split, and this was split into a training and validation set. For reproducibility, the data was shuffled after loading in using data.sample() with only the hyperparameters frac=1 and random_state=42 used. I split the data approximately 90-10, with 122,000 rows in the train set and the remainder in the validation set.

### Training Procedure

<!-- This relates heavily to the Technical Specifications. Content here should link to that section when it is relevant to the training procedure. -->
A Program of Thought (PoT) prompting approach was used to modify the training data. PoT specifically focuses on generating structured, step-by-step reasoning in a more formalized and executable format than chain of thought. With PoT, the model generates a sequence of logical steps that resemble pseudo-code, which can then be translated into actual code. PoT should allow structured reasoning for code generation, should be able to debug broken code, and should provide a step-by-step breakdown of the plan ([Chen et al., 2023](https://arxiv.org/abs/2211.12588)).

PoT was implemented by creating a new column in the dataset that initiated a “plan” for the model to follow. The plan was a 4-step process: analyze the question from the train column, think step by step and plan an efficient solution before writing the code, consider any necessary programming constructs or tools, and explain the approach with well-organized and documented code. The answer to the question from the dataset was appended after the plan so there was a single text block for training. Lastly, before training started, the pandas dataframes (train and validation) were converted into Hugging Face Dataset objects, and the tokenizer was applied to the newly created column for each row.

LoRA was used as the training method. LoRA can efficiently update a subset of the model parameters through the introduction of low-rank matrices into weight updates, which reduces the computational overhead compared to a full fine-tuning approach while also preserving the pre-trained knowledge of the base model. This is a big advantage when using a relatively large model like Mistral-7B. Compared to other training approaches like prompt tuning, LoRA appears to be better at systematic reasoning and can be used to integrate new knowledge into the model. While LoRA will still demand relatively large amounts of computational resources compared to a simpler method like prompt tuning, this drawback is outweighed by LoRA’s ability to adapt the model effectively for a complex task such as this. LoRA’s balance of scalability, task-specific adaptability, and preservation of the model’s foundational knowledge make it the ideal choice for achieving high scores on all tested benchmarks.

In order to see all of the hyperparameters used to train the model, look at the ‘Training Hyperparameters’ section below. An r of 64 offers a trade-off between parameter efficiency and expressiveness. Setting lora_alpha = r sets the scaling factor to 1.0 and helps stabilize training without overpowering the base model’s representations. A lora_dropout of 0.05 adds regularization to prevent overfitting and typically is low enough to not be too aggressive to harm learning but still provide generalization. I chose ‘q_proj’ and ‘v_proj’ as the target modules since these attention layers have been shown to have high impact and are efficient for downstream task performance. For the training arguments, a learning rate of 1e-5 was used, as this prevents the LoRA layers from diverging too fast or corrupting the base model’s latent space, which preserves pre-trained knowledge. Additionally, the model was trained on 2 epochs, given that LoRA models tend to adapt quickly since only a percentage of the parameters are trained.

#### Training Hyperparameters

```python
from transformers import TrainingArguments
from peft import get_peft_model, LoraConfig

lora_config = LoraConfig(
    r = 64,
    lora_alpha = 64,
    lora_dropout = 0.05,
    bias = "none",
    task_type = "CAUSAL_LM",
    target_modules = ['q_proj', 'v_proj']
)
model = get_peft_model(model, lora_config)

def create_training_arguments(path, learning_rate = 0.00001, epochs=2, eval_steps=12000):
    training_args = TrainingArguments(
        output_dir = path,
        auto_find_batch_size = True,
        learning_rate = learning_rate,
        num_train_epochs = epochs,
        logging_steps = eval_steps,
        eval_strategy = "steps",
        eval_steps = eval_steps,
        save_steps = eval_steps,
        load_best_model_at_end = True
    )
    return training_args
```


## Evaluation

<!-- This section describes the evaluation protocols and provides the results. -->

### Testing Data, Factors & Metrics

#### Testing Data

<!-- This should link to a Dataset Card if possible. -->

The model was tested on three benchmarks: [Mostly Basic Python Problems (MBPP)](https://github.com/google-research/google-research/tree/master/mbpp), [HumanEval](https://github.com/openai/human-eval), and [Massive Multitask Language Understanding (MMLU)](https://huggingface.co./datasets/cais/mmlu). The first two benchmarks aim to assess the model's Python coding capability, and the third benchmark aims to assess the model's generalizability. The entirety of these datasets was used to test the model.

#### Metrics

<!-- These are the evaluation metrics being used, ideally with a description of why. -->

The MBPP benchmark was chosen because it will assess the model’s ability to understand basic programming concepts in the Python language, show the model’s ability to solve simple and well-defined problems, and show if the model is producing correct code for fundamental programming tasks. Similar to this fine-tuned model, the input structure of the MBPP benchmark is a problem description in natural language, and the output is a Python code solution that is expected to handle the given test cases ([Austin et al., 2021](https://arxiv.org/abs/2108.07732)).

The HumanEval benchmark was chosen as it will assess if the model is overfit for code generation by looking at its basic Python programming capabilities, problem-solving skills, and code correctness through test cases and ensure the model maintains fundamental coding abilities. The input structure is a function signature and doctoring with a description of its function, and the output structure is a complete function implementation in Python ([Chen et al., 2021](https://arxiv.org/abs/2107.03374)). The problems in the HumanEval benchmark are more complex than the problems presented in the MBPP benchmark and, therefore, allow for a comprehensive overview of the model's ability to solve Python coding problems.

The MMLU benchmark is being used to assess the general knowledge and reasoning ability of the model. While the model's generalizability is not the priority, I thought it would be helpful to know if the model can be used on other types of tasks. The MMLU benchmark will show if there is catastrophic forgetting from the base model. The input structure is a question with multiple-choice answer options from one of 57 different subjects, and the output is the model's selected answer.

### Results

The current model was compared to the base [Mistral-7B](https://huggingface.co./mistralai/Mistral-7B-v0.1) model for full disclosure on whether, and to what degree, the model improved. Additionally, the model was compared to the [DeepSeek-R1](https://huggingface.co./deepseek-ai/DeepSeek-R1-Distill-Qwen-7B) model and the [OpenHands LM v0.1](https://huggingface.co./all-hands/openhands-lm-7b-v0.1) model, which each have a similar number of parameters. I was interested to see how newer LLMs compared to relatively older models.

DeepSeek-R1 is a reasoning model, and I wanted to see how a generalized reasoning model would perform on a specific reasoning task. The DeepSeek-R1 model was introduced a little more than 1 year after the base Mistral model was introduced (January 2025 vs. September 2023). Note that DeepSeek-R1 was not considered for the base model due to concern DeepSeek may be banned in the United States during the project.

OpenHands LM v0.1 is a specialized model built for a wide range of coding tasks and languages. I was interested to see how a model trained for a specific language measures up to a general coding model. The OpenHands LM v0.1 was introduced more recently than all the other comparison models in March 2025. Note that OpenHands LM v0.1 could not be the base model since it did not exist at the start of the project.

|       Benchmark       | Custom-Coding LLM | Base Mistral-7B | DeepSeek R1-7B | OpenHands LM v0.1-7B |
|:---------------------:|:-----------------:|:---------------:|:--------------:|:---------------:|
|    MBPP (at 1-pass)   |        40.2       |       37.6      |      47.8      |       61.8      |
| HumanEval (at 1-pass) |         0         |       0.6       |      11.6      |       80.5      |
|          MMLU         |        59.2       |       59.6      |      52.6      |       64.6      |

#### Summary

The model has a slight overall performance improvement compared to the base model. While the HumanEval score dropped at 1-pass, the structure of the generated code is actually improved compared to the base model; despite the slightly lower score, the code appears to be more helpful for a user. There is no evidence of catastrophic forgetting due to the similar MMLU scores.

The model has better generalizability than DeepSeek R1, but DeepSeek R1 seems to be superior in solving and reasoning through Python problems. The greatest difference in DeepSeek from the current custom model is the HumanEval score at 1-pass, for which DeepSeek has a significant advantage.

OpenHands LM v0.1 has a superior performance in all tested benchmarks relative to each comparison model, particularly in the HumanEval benchmark, where it blew away the competition but boasts a strong MBPP score as well. The current custom model did not perform as well as this model.

In conclusion, the model shows improvement in the task compared to the base model but does not perform as well as the newer LLMs. Implementing some of the techniques used in these newer models may be able to yield even more improvement in the current custom-coding LLM.

## Model Card Contact

- **Email:** [email protected]
- **LinkedIn:** [Alden Swain](https://www.linkedin.com/in/alden-swain-747108328/)