初始化项目,由ModelHub XC社区提供模型
Model: AXONVERTEX-AI-RESEARCH/qwen2.5-0.5b-pii-anonymizer Source: Original Platform
This commit is contained in:
36
.gitattributes
vendored
Normal file
36
.gitattributes
vendored
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
*.7z filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.arrow filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.bin filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.bz2 filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.ckpt filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.ftz filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.gz filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.h5 filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.joblib filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.lfs.* filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.mlmodel filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.model filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.msgpack filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.npy filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.npz filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.onnx filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.ot filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.parquet filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.pb filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.pickle filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.pkl filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.pt filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.pth filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.rar filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.safetensors filter=lfs diff=lfs merge=lfs -text
|
||||||
|
saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.tar.* filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.tar filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.tflite filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.tgz filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.wasm filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.xz filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.zip filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.zst filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
||||||
|
tokenizer.json filter=lfs diff=lfs merge=lfs -text
|
||||||
207
LICENSE.md
Normal file
207
LICENSE.md
Normal file
@@ -0,0 +1,207 @@
|
|||||||
|
# Composite License
|
||||||
|
|
||||||
|
This model and its associated artifacts are subject to a **composite license** reflecting the terms of all upstream components used in training and construction. Users must comply with **all** applicable licenses below.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Base Model — Qwen2.5-0.5B-Instruct
|
||||||
|
|
||||||
|
**License**: Apache License 2.0
|
||||||
|
**Licensor**: Qwen Team, Alibaba Cloud
|
||||||
|
**Source**: https://huggingface.co/Qwen/Qwen2.5-0.5B-Instruct
|
||||||
|
|
||||||
|
```
|
||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License.
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship submitted to the
|
||||||
|
Licensor for inclusion in the Work.
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any Legal Entity on behalf
|
||||||
|
of whom a Contribution has been received by the Licensor.
|
||||||
|
|
||||||
|
2. Grant of Copyright License.
|
||||||
|
Subject to the terms and conditions of this License, each Contributor
|
||||||
|
hereby grants to You a perpetual, worldwide, non-exclusive, no-charge,
|
||||||
|
royalty-free, irrevocable copyright license to reproduce, prepare
|
||||||
|
Derivative Works of, publicly display, publicly perform, sublicense,
|
||||||
|
and distribute the Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License.
|
||||||
|
Subject to the terms and conditions of this License, each Contributor
|
||||||
|
hereby grants to You a perpetual, worldwide, non-exclusive, no-charge,
|
||||||
|
royalty-free, irrevocable patent license to make, have made, use,
|
||||||
|
offer to sell, sell, import, and otherwise transfer the Work.
|
||||||
|
|
||||||
|
4. Redistribution.
|
||||||
|
You may reproduce and distribute copies of the Work or Derivative Works
|
||||||
|
thereof in any medium, with or without modifications, and in Source or
|
||||||
|
Object form, provided that You meet the following conditions:
|
||||||
|
(a) You must give any other recipients of the Work or Derivative Works
|
||||||
|
a copy of this License; and
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works that
|
||||||
|
You distribute, all copyright, patent, trademark, and attribution
|
||||||
|
notices from the Source form of the Work; and
|
||||||
|
(d) If the Work includes a "NOTICE" text file, You must include a
|
||||||
|
readable copy of the attribution notices contained therein.
|
||||||
|
|
||||||
|
5. Submission of Contributions.
|
||||||
|
Unless You explicitly state otherwise, any Contribution intentionally
|
||||||
|
submitted for inclusion in the Work shall be under the terms and
|
||||||
|
conditions of this License, without any additional terms or conditions.
|
||||||
|
|
||||||
|
6. Trademarks.
|
||||||
|
This License does not grant permission to use the trade names,
|
||||||
|
trademarks, service marks, or product names of the Licensor.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty.
|
||||||
|
The Work is provided on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||||
|
CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
|
||||||
|
8. Limitation of Liability.
|
||||||
|
In no event shall any Contributor be liable for any damages arising
|
||||||
|
as a result of this License or out of the use or inability to use the Work.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability.
|
||||||
|
You may choose to offer, and charge a fee for, acceptance of support,
|
||||||
|
warranty, indemnity, or other liability obligations consistent with
|
||||||
|
this License.
|
||||||
|
|
||||||
|
END OF APACHE 2.0 TERMS
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. Training Dataset — nvidia/Nemotron-PII
|
||||||
|
|
||||||
|
**License**: Creative Commons Attribution 4.0 International (CC-BY-4.0)
|
||||||
|
**Licensor**: NVIDIA Corporation
|
||||||
|
**Source**: https://huggingface.co/datasets/nvidia/Nemotron-PII
|
||||||
|
|
||||||
|
### Summary of CC-BY-4.0
|
||||||
|
|
||||||
|
You are free to:
|
||||||
|
- **Share** — copy and redistribute the material in any medium or format for any purpose, including commercially.
|
||||||
|
- **Adapt** — remix, transform, and build upon the material for any purpose, including commercially.
|
||||||
|
|
||||||
|
Under the following terms:
|
||||||
|
- **Attribution** — You must give appropriate credit, provide a link to the license, and indicate if changes were made.
|
||||||
|
|
||||||
|
Full text: https://creativecommons.org/licenses/by/4.0/legalcode
|
||||||
|
|
||||||
|
### Required Attribution
|
||||||
|
|
||||||
|
This model was trained using the Nemotron-PII dataset by NVIDIA Corporation, licensed under CC-BY-4.0. The dataset contains 100,000 synthetic English records with span-level PII/PHI annotations across 50+ industries, generated with NVIDIA NeMo Data Designer.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. Training Dataset — ai4privacy/pii-masking-200k
|
||||||
|
|
||||||
|
**License**: AI4Privacy Free/Corporate License
|
||||||
|
**Licensor**: AI4Privacy, Ai Suisse SA
|
||||||
|
**Source**: https://huggingface.co/datasets/ai4privacy/pii-masking-200k
|
||||||
|
**Contact**: licensing@ai4privacy.com
|
||||||
|
|
||||||
|
### Free License
|
||||||
|
|
||||||
|
Copyright © 2023 Ai4Privacy (Ai Suisse SA)
|
||||||
|
|
||||||
|
#### Qualification Criteria
|
||||||
|
|
||||||
|
You are qualified to use the AI4Privacy dataset and derivative works at no cost if you are:
|
||||||
|
|
||||||
|
- An individual
|
||||||
|
- A for-profit entity with a staff count of up to 3
|
||||||
|
- A non-profit or not-for-profit organization
|
||||||
|
- In the stage of assessing suitability, and have not yet applied it commercially
|
||||||
|
|
||||||
|
#### Permitted Use Cases
|
||||||
|
|
||||||
|
Eligible persons may use the dataset and derivative works for non-commercial or commercial purposes. Users may also modify the dataset to meet specific needs.
|
||||||
|
|
||||||
|
#### Prohibited Use Cases
|
||||||
|
|
||||||
|
It is not permissible to duplicate or alter the dataset with the intention to distribute, sell, rent, license, re-license, or sublicense your own derivative.
|
||||||
|
|
||||||
|
#### Warranty Notice
|
||||||
|
|
||||||
|
The dataset comes "AS IS", without any express or implied warranties, including but not limited to warranties of saleability, suitability for a specific use, and non-infringement. The authors or copyright holders shall not be responsible for any claim, damage or other liability, whether in a contract, tort or otherwise, arising from or in connection with the dataset or its use.
|
||||||
|
|
||||||
|
### Corporate License
|
||||||
|
|
||||||
|
If your entity does not fall under the category eligible for a free license (i.e., a for-profit organization with more than 3 employees), you **must** procure a corporate license to use this model or any derivative works based on the AI4Privacy dataset.
|
||||||
|
|
||||||
|
**Contact**: licensing@ai4privacy.com
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. Training Framework — Unsloth
|
||||||
|
|
||||||
|
**License**: Apache License 2.0
|
||||||
|
**Source**: https://github.com/unslothai/unsloth
|
||||||
|
|
||||||
|
Licensed under the same Apache 2.0 terms as detailed in Section 1 above.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. Composite License Summary
|
||||||
|
|
||||||
|
**The effective license for this model is the most restrictive combination of all upstream licenses.** In practice, this means:
|
||||||
|
|
||||||
|
| User Type | Can Use This Model? | Requirements |
|
||||||
|
|-----------|-------------------|--------------|
|
||||||
|
| Individuals | Yes, freely | Attribution for Nemotron-PII (CC-BY-4.0) |
|
||||||
|
| Non-profits | Yes, freely | Attribution for Nemotron-PII (CC-BY-4.0) |
|
||||||
|
| Small businesses (≤3 employees) | Yes, freely | Attribution for Nemotron-PII (CC-BY-4.0) |
|
||||||
|
| Larger commercial entities (>3 employees) | Requires corporate license from AI4Privacy | Contact licensing@ai4privacy.com + Attribution for Nemotron-PII |
|
||||||
|
|
||||||
|
### Attribution Notice
|
||||||
|
|
||||||
|
This model incorporates or derives from:
|
||||||
|
|
||||||
|
1. **Qwen2.5-0.5B-Instruct** by Qwen Team, Alibaba Cloud — Apache 2.0
|
||||||
|
2. **Nemotron-PII** by NVIDIA Corporation — CC-BY-4.0
|
||||||
|
3. **PII Masking 200K** by AI4Privacy, Ai Suisse SA — AI4Privacy Free/Corporate License
|
||||||
|
4. **Unsloth** by Unsloth AI — Apache 2.0
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. Disclaimer
|
||||||
|
|
||||||
|
THE MODEL AND ALL ASSOCIATED ARTIFACTS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS, COPYRIGHT HOLDERS, OR CONTRIBUTORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE MODEL OR THE USE OR OTHER DEALINGS IN THE MODEL.
|
||||||
|
|
||||||
|
This model is NOT a substitute for professional legal, compliance, or data protection review. Users are solely responsible for ensuring their use of this model complies with applicable laws and regulations including but not limited to GDPR, HIPAA, CCPA, and other data protection frameworks.
|
||||||
686
README.md
Normal file
686
README.md
Normal file
@@ -0,0 +1,686 @@
|
|||||||
|
---
|
||||||
|
license: other
|
||||||
|
license_name: composite-license
|
||||||
|
license_link: LICENSE.md
|
||||||
|
language:
|
||||||
|
- en
|
||||||
|
- fr
|
||||||
|
- de
|
||||||
|
- it
|
||||||
|
tags:
|
||||||
|
- pii
|
||||||
|
- anonymization
|
||||||
|
- privacy
|
||||||
|
- synthetic-data
|
||||||
|
- qlora
|
||||||
|
- unsloth
|
||||||
|
- data-privacy
|
||||||
|
- gdpr
|
||||||
|
- hipaa
|
||||||
|
- named-entity-recognition
|
||||||
|
- text-rewriting
|
||||||
|
base_model: Qwen/Qwen2.5-0.5B-Instruct
|
||||||
|
datasets:
|
||||||
|
- nvidia/Nemotron-PII
|
||||||
|
- ai4privacy/pii-masking-200k
|
||||||
|
pipeline_tag: text-generation
|
||||||
|
model-index:
|
||||||
|
- name: qwen2.5-0.5b-pii-anonymizer
|
||||||
|
results: []
|
||||||
|
---
|
||||||
|
|
||||||
|
# qwen2.5-0.5b-pii-anonymizer
|
||||||
|
|
||||||
|
A **context-aware PII anonymization model** fine-tuned from [Qwen2.5-0.5B-Instruct](https://huggingface.co/Qwen/Qwen2.5-0.5B-Instruct). Unlike traditional redaction tools that insert ugly `[REDACTED]` or `<PERSON>` placeholders, this model **replaces personally identifiable information with realistic synthetic data** while preserving the original grammar, formatting, tone, and semantic flow of the text.
|
||||||
|
|
||||||
|
This is **Phase 1** of an enterprise grade PII anonymization pipeline. THIS CANNOT BE USED FOR ANY COMMERCIAL PURPOSE WITHOUT LICENSE APPROVAL FROM AI4PRIVACY. Phase 2 combines this model with [Microsoft Presidio](https://github.com/microsoft/presidio) and [GLiNER](https://github.com/urchade/GLiNER) for production-grade, compliance-ready deployment.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Table of Contents
|
||||||
|
|
||||||
|
- [What This Model Does](#what-this-model-does)
|
||||||
|
- [Why Context-Aware Rewriting](#why-context-aware-rewriting)
|
||||||
|
- [Training Details](#training-details)
|
||||||
|
- [Datasets](#datasets)
|
||||||
|
- [Data Engineering Pipeline](#data-engineering-pipeline)
|
||||||
|
- [Model Architecture & Fine-Tuning](#model-architecture--fine-tuning)
|
||||||
|
- [Training Infrastructure](#training-infrastructure)
|
||||||
|
- [Training Results](#training-results)
|
||||||
|
- [Inference Examples](#inference-examples)
|
||||||
|
- [Usage](#usage)
|
||||||
|
- [Quick Start — Test It in 30 Seconds](#quick-start--test-it-in-30-seconds)
|
||||||
|
- [Run the Full Test Suite](#run-the-full-test-suite--see-results-across-12-pii-categories)
|
||||||
|
- [With Unsloth (2× Faster)](#with-unsloth-2-faster-inference-60-less-memory)
|
||||||
|
- [Batch Processing](#batch-processing--anonymize-multiple-documents)
|
||||||
|
- [Process a File Line-by-Line](#process-a-file-line-by-line)
|
||||||
|
- [Integration with Pandas DataFrames](#integration-with-pandas-dataframes)
|
||||||
|
- [Known Limitations](#known-limitations)
|
||||||
|
- [Phase 2 Roadmap](#phase-2-roadmap)
|
||||||
|
- [License](#license)
|
||||||
|
- [Citation](#citation)
|
||||||
|
- [Acknowledgments](#acknowledgments)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## What This Model Does
|
||||||
|
|
||||||
|
Given any text containing personally identifiable information, the model outputs the **same text** with all PII replaced by realistic, contextually appropriate synthetic entities:
|
||||||
|
|
||||||
|
| PII Type | Input | Output |
|
||||||
|
|----------|-------|--------|
|
||||||
|
| Names | "Dear Mr. Arjun Mehta" | "Dear Mr. John Davis" |
|
||||||
|
| Emails | "sarah.johnson@globalfinance.com" | "jason69@example.net" |
|
||||||
|
| Phone numbers | "+91-22-4567-8901" | "001-727-944-3626" |
|
||||||
|
| SSN | "SSN: 321-45-6789" | "SSN: 458-78-3375" |
|
||||||
|
| Addresses | "42 Baker Street, London" | "50783 Wilson Stream, New York" |
|
||||||
|
| Passport | "Passport L8472910" | "Passport xQyFZbWd" |
|
||||||
|
| Mixed PII | "I'm David Chen (david.chen@techcorp.io, +1-415-555-0198)" | "I'm Michael Smith (kathleen32@example.com, 676-297-4529)" |
|
||||||
|
|
||||||
|
The model handles 55+ PII categories across corporate, medical, financial, conversational, and multilingual contexts.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Why Context-Aware Rewriting
|
||||||
|
|
||||||
|
Traditional PII tools fall into two camps, each with significant drawbacks:
|
||||||
|
|
||||||
|
**Rule-based redaction** (regex, Presidio alone) catches structured patterns well (SSNs, credit cards) but produces unreadable output filled with `[PERSON]` and `[ADDRESS]` tokens. This breaks downstream NLP tasks, makes documents unusable for analytics, and is immediately obvious to anyone reading the text.
|
||||||
|
|
||||||
|
**Naive masking** (simple find-and-replace) often breaks grammar, misses contextual PII like "my boss David" or "send it to the Baker Street office", and can't handle the same entity appearing in different syntactic roles.
|
||||||
|
|
||||||
|
**This model combines both strengths**: it understands context deeply enough to identify PII that rule-based systems miss, while generating natural-sounding replacements that maintain document utility. A medical record that says "Patient: Robert Williams, DOB: 1985-04-12" becomes "Patient: Michael Rodriguez, DOB: 1976-03-25" — still perfectly usable for analytics, training other models, or sharing with third parties.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Training Details
|
||||||
|
|
||||||
|
### Summary
|
||||||
|
|
||||||
|
| Parameter | Value |
|
||||||
|
|-----------|-------|
|
||||||
|
| **Base model** | [Qwen/Qwen2.5-0.5B-Instruct](https://huggingface.co/Qwen/Qwen2.5-0.5B-Instruct) |
|
||||||
|
| **Parameters** | 502.8M total, 8.8M trainable (1.75%) |
|
||||||
|
| **Method** | QLoRA (4-bit NF4 quantization + LoRA r=16) |
|
||||||
|
| **Framework** | [Unsloth](https://github.com/unslothai/unsloth) + HuggingFace TRL |
|
||||||
|
| **Training samples** | 309,225 (after validation filtering) |
|
||||||
|
| **Train/eval split** | 293,763 / 15,462 (95/5) |
|
||||||
|
| **Epochs** | 2 |
|
||||||
|
| **Batch size** | 64 |
|
||||||
|
| **Total steps** | 9,182 |
|
||||||
|
| **Learning rate** | 2e-4 (cosine schedule, 100 warmup steps) |
|
||||||
|
| **Optimizer** | AdamW 8-bit |
|
||||||
|
| **Precision** | bfloat16 |
|
||||||
|
| **Final training loss** | 1.0588 |
|
||||||
|
| **Training time** | ~2.3 hours |
|
||||||
|
| **Hardware** | NVIDIA RTX PRO 6000 Blackwell (95.6 GB VRAM) |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Datasets
|
||||||
|
|
||||||
|
This model was trained on a merged corpus from two high-quality open-source PII datasets:
|
||||||
|
|
||||||
|
### nvidia/Nemotron-PII
|
||||||
|
|
||||||
|
- **Source**: [huggingface.co/datasets/nvidia/Nemotron-PII](https://huggingface.co/datasets/nvidia/Nemotron-PII)
|
||||||
|
- **Size**: 100,000 English records
|
||||||
|
- **License**: CC-BY-4.0
|
||||||
|
- **Description**: A synthetic, persona-grounded dataset for PII/PHI detection. Contains span-level annotations for 55+ PII/PHI categories across 50+ industries, generated with NVIDIA NeMo Data Designer using synthetic personas grounded in U.S. Census data. Includes both structured (forms, invoices) and unstructured (emails, free text) documents.
|
||||||
|
- **Categories covered**: first_name, last_name, date_of_birth, street_address, email, phone_number, ssn, credit_card, company_name, vehicle_identifier, url, blood_type, employment_status, and 40+ more.
|
||||||
|
|
||||||
|
### ai4privacy/pii-masking-200k
|
||||||
|
|
||||||
|
- **Source**: [huggingface.co/datasets/ai4privacy/pii-masking-200k](https://huggingface.co/datasets/ai4privacy/pii-masking-200k)
|
||||||
|
- **Size**: 209,261 multilingual records (English, French, German, Italian)
|
||||||
|
- **License**: AI4Privacy Free/Corporate License (see LICENSE.md)
|
||||||
|
- **Description**: Built by AI4Privacy (Ai Suisse SA) using the p5y framework with human-in-the-loop validation. Features diverse real-world PII scenarios across multiple domains and languages. Contains span-level privacy masks with entity types and positions.
|
||||||
|
- **Categories covered**: FIRSTNAME, LASTNAME, EMAIL, PHONE, STREETADDRESS, CITY, ZIPCODE, COUNTRY, JOBAREA, JOBTYPE, CREDITCARDNUMBER, IBAN, BITCOINADDRESS, VEHICLEVIN, USERAGENT, and 30+ more.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Data Engineering Pipeline
|
||||||
|
|
||||||
|
Neither dataset provides ready-made "input → synthetic output" pairs. A custom data engineering pipeline was built to transform both datasets into training-ready format.
|
||||||
|
|
||||||
|
### The Challenge
|
||||||
|
|
||||||
|
- **Nvidia Nemotron-PII** provides `text` (raw) + `spans` (PII positions with labels), but no synthetic replacements. The spans use Python-style single-quoted dictionaries (not JSON), requiring `ast.literal_eval` for parsing.
|
||||||
|
- **AI4Privacy** provides `source_text` (raw) + `target_text` (with `[LABEL]` mask tokens, not synthetic data) + `privacy_mask` (PII values with positions and labels).
|
||||||
|
|
||||||
|
### The Solution
|
||||||
|
|
||||||
|
Both datasets were processed through a label-aware synthetic data generation pipeline using [Faker](https://faker.readthedocs.io/):
|
||||||
|
|
||||||
|
```
|
||||||
|
[Raw text + PII span annotations]
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
[Parse spans (ast.literal_eval for Nvidia, JSON for AI4Privacy)]
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
[Sort spans by position (descending) to preserve indices during replacement]
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
[For each span: generate synthetic value via label→Faker mapping]
|
||||||
|
first_name → fake.first_name()
|
||||||
|
email → fake.email()
|
||||||
|
ssn → fake.ssn()
|
||||||
|
street_addr → fake.street_address()
|
||||||
|
phone → fake.phone_number()
|
||||||
|
... (55+ label types mapped)
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
[Validate: non-empty, changed from original, structurally coherent]
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
[Format as ChatML: system instruction + user input + assistant output]
|
||||||
|
```
|
||||||
|
|
||||||
|
**Results**: 99,994 valid pairs from Nvidia (6 skipped) + 209,231 from AI4Privacy (30 skipped) = **309,225 total training samples**.
|
||||||
|
|
||||||
|
### ChatML Format
|
||||||
|
|
||||||
|
Every training sample follows the Qwen ChatML template:
|
||||||
|
|
||||||
|
```
|
||||||
|
<|im_start|>system
|
||||||
|
You are an enterprise data privacy engine. Analyze the input text, identify all
|
||||||
|
Personally Identifiable Information (PII), and output the text with the PII seamlessly
|
||||||
|
replaced by realistic synthetic data. Maintain the exact original formatting, syntax,
|
||||||
|
and tone.<|im_end|>
|
||||||
|
<|im_start|>user
|
||||||
|
I, Jason, am applying for a financial services account. My date of birth is
|
||||||
|
1987-05-22. I live at 87 Avenida De La Estrella.<|im_end|>
|
||||||
|
<|im_start|>assistant
|
||||||
|
I, Jeffery, am applying for a financial services account. My date of birth is
|
||||||
|
1947-04-28. I live at 43321 Brittany Bypass.<|im_end|>
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Model Architecture & Fine-Tuning
|
||||||
|
|
||||||
|
### Base Model: Qwen2.5-0.5B-Instruct
|
||||||
|
|
||||||
|
Selected for its optimal balance of speed and linguistic capability at 500M parameters:
|
||||||
|
|
||||||
|
- **Architecture**: Dense Causal LM with RoPE (Rotary Position Embedding), SwiGLU activation, and Grouped-Query Attention (GQA)
|
||||||
|
- **Vocabulary**: 151,936 tokens (large vocab enables strong multilingual performance)
|
||||||
|
- **Context window**: 2,048 tokens (sufficient for document-level PII rewriting)
|
||||||
|
- **License**: Apache 2.0
|
||||||
|
|
||||||
|
### QLoRA Configuration
|
||||||
|
|
||||||
|
The base model weights are frozen with 4-bit NormalFloat (NF4) quantization. Low-Rank Adaptation (LoRA) matrices are injected across **all** linear projections:
|
||||||
|
|
||||||
|
| Parameter | Value | Rationale |
|
||||||
|
|-----------|-------|-----------|
|
||||||
|
| Rank (r) | 16 | Good capacity-to-memory ratio for 0.5B models |
|
||||||
|
| Alpha (α) | 16 | α/r = 1.0 effective scaling factor |
|
||||||
|
| Target modules | q_proj, k_proj, v_proj, o_proj, gate_proj, up_proj, down_proj | Full coverage for deep contextual rewriting |
|
||||||
|
| Dropout | 0 | Clean SFT data doesn't need dropout regularization |
|
||||||
|
| Gradient checkpointing | Unsloth optimized | 30% memory savings |
|
||||||
|
| Trainable parameters | 8,798,208 / 502,830,976 | 1.75% of total |
|
||||||
|
|
||||||
|
### Training Hyperparameters
|
||||||
|
|
||||||
|
| Parameter | Value |
|
||||||
|
|-----------|-------|
|
||||||
|
| Batch size | 64 per device |
|
||||||
|
| Gradient accumulation | 1 |
|
||||||
|
| Effective batch size | 64 |
|
||||||
|
| Epochs | 2 |
|
||||||
|
| Learning rate | 2e-4 |
|
||||||
|
| LR scheduler | Cosine decay |
|
||||||
|
| Warmup steps | 100 |
|
||||||
|
| Weight decay | 0.01 |
|
||||||
|
| Optimizer | AdamW 8-bit |
|
||||||
|
| Precision | bfloat16 |
|
||||||
|
| Seed | 3407 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Training Results
|
||||||
|
|
||||||
|
### Loss Curve
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
The training loss shows healthy convergence:
|
||||||
|
|
||||||
|
- **Starting loss**: 2.65 (step 10)
|
||||||
|
- **Rapid descent**: 2.65 → 1.25 in the first 300 steps
|
||||||
|
- **Gradual refinement**: 1.25 → 1.00 over remaining steps
|
||||||
|
- **Final loss**: 1.0588 (stable, no oscillation)
|
||||||
|
- **No overfitting**: Loss continues decreasing smoothly through epoch 2
|
||||||
|
|
||||||
|
### Training Metrics
|
||||||
|
|
||||||
|
| Metric | Value |
|
||||||
|
|--------|-------|
|
||||||
|
| Final training loss | 1.0588 |
|
||||||
|
| Training runtime | 8,189 seconds (~2.3 hours) |
|
||||||
|
| Samples per second | 71.7 |
|
||||||
|
| Steps per second | 1.12 |
|
||||||
|
| Total FLOPs | 1.29 × 10¹⁸ |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Inference Examples
|
||||||
|
|
||||||
|
Results from the post-training evaluation on 12 diverse PII scenarios:
|
||||||
|
|
||||||
|
| # | Category | Input | Output |
|
||||||
|
|---|----------|-------|--------|
|
||||||
|
| 1 | Names | Dear Mr. Arjun Mehta, your appointment with Dr. Priya Sharma is confirmed for July 15th. | Dear John Davis, your appointment with Dr. Michael Johnson is confirmed for 2006-04-18. |
|
||||||
|
| 2 | Emails | contact sarah.johnson@globalfinance.com or accounts@globalfinance.com | contact jason69@example.net or smithmichael@example.org |
|
||||||
|
| 3 | Phone | Call our Mumbai office at +91-22-4567-8901 | Call our Port Michaelborough office at 001-727-944-3626x015 |
|
||||||
|
| 4 | Address | Ship to 42 Baker Street, London, NW1 6XE, United Kingdom | Ship to 50783 Wilson Stream Suite 979, New York |
|
||||||
|
| 5 | National ID | Aadhaar ID 2345-6789-0123 issued to Neha Gupta | Aadhaar ID cHkYtWjJwQXz issued to Christopher Jones |
|
||||||
|
| 6 | Financial | Payment on Visa ending 4829. Ref: TXN-2024-09-17-0042 | Payment on Visa ending 4829. Ref: TXN-1963-12-15-0042 |
|
||||||
|
| 7 | Mixed PII | I'm David Chen (david.chen@techcorp.io, +1-415-555-0198) | I'm Michael Smith (kathleen32@example.com, 676-297-4529x992) |
|
||||||
|
| 8 | Passport | Passport L8472910 belonging to Maria Gonzalez | Passport xQyFZbWd belonging to Christopher Williams |
|
||||||
|
| 9 | Medical | Patient: Robert Williams, DOB: 1985-04-12, MRN: MED-2024-88451 | Patient: Michael Rodriguez, DOB: 1976-03-25, MRN: MED-2024-88451 |
|
||||||
|
| 10 | Employee | Name: Tanaka Yuki, SSN: 321-45-6789 | Name: Williams James, SSN: 458-78-3375 |
|
||||||
|
| 11 | Informal | Hey Lisa, it's Mike from the gym. Text me at 555-867-5309 | Hey Michael, it's David from the gym. Text me at 412.938.3297x641 |
|
||||||
|
| 12 | Hindi-English | Ramesh ji ka address hai 14, MG Road, Pune 411001 | Lori ji ka address hai 92953 Michael Plaza Suite 825 |
|
||||||
|
|
||||||
|
**Coherence check**: All 12 samples passed — no empty outputs, no placeholder tokens, all outputs structurally coherent with the input.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
### Quick Start — Test It in 30 Seconds
|
||||||
|
|
||||||
|
```python
|
||||||
|
# pip install transformers torch accelerate
|
||||||
|
|
||||||
|
from transformers import AutoModelForCausalLM, AutoTokenizer
|
||||||
|
|
||||||
|
MODEL_NAME = "AXONVERTEX-AI-RESEARCH/qwen2.5-0.5b-pii-anonymizer"
|
||||||
|
|
||||||
|
model = AutoModelForCausalLM.from_pretrained(MODEL_NAME, device_map="auto")
|
||||||
|
tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME)
|
||||||
|
|
||||||
|
def anonymize(text):
|
||||||
|
"""Anonymize PII in the given text and return the result."""
|
||||||
|
messages = [
|
||||||
|
{"role": "system", "content": (
|
||||||
|
"You are an enterprise data privacy engine. Analyze the input text, identify all "
|
||||||
|
"Personally Identifiable Information (PII), and output the text with the PII seamlessly "
|
||||||
|
"replaced by realistic synthetic data. Maintain the exact original formatting, syntax, "
|
||||||
|
"and tone."
|
||||||
|
)},
|
||||||
|
{"role": "user", "content": text},
|
||||||
|
]
|
||||||
|
inputs = tokenizer.apply_chat_template(
|
||||||
|
messages, tokenize=True, add_generation_prompt=True, return_tensors="pt"
|
||||||
|
).to(model.device)
|
||||||
|
|
||||||
|
outputs = model.generate(
|
||||||
|
inputs,
|
||||||
|
max_new_tokens=512,
|
||||||
|
temperature=0.3,
|
||||||
|
top_p=0.9,
|
||||||
|
do_sample=True,
|
||||||
|
)
|
||||||
|
return tokenizer.decode(outputs[0][inputs.shape[-1]:], skip_special_tokens=True)
|
||||||
|
|
||||||
|
# Try it
|
||||||
|
result = anonymize("Hi, I'm John Doe. Email me at john.doe@acme.com or call +1-555-867-5309.")
|
||||||
|
print(result)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Run the Full Test Suite — See Results Across 12 PII Categories
|
||||||
|
|
||||||
|
Copy and run this script to test the model against names, emails, phones, addresses, national IDs, financial data, passports, medical records, employee records, informal text, and multilingual input:
|
||||||
|
|
||||||
|
```python
|
||||||
|
# pip install transformers torch accelerate
|
||||||
|
|
||||||
|
from transformers import AutoModelForCausalLM, AutoTokenizer
|
||||||
|
|
||||||
|
MODEL_NAME = "AXONVERTEX-AI-RESEARCH/qwen2.5-0.5b-pii-anonymizer"
|
||||||
|
model = AutoModelForCausalLM.from_pretrained(MODEL_NAME, device_map="auto")
|
||||||
|
tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME)
|
||||||
|
|
||||||
|
SYSTEM_PROMPT = (
|
||||||
|
"You are an enterprise data privacy engine. Analyze the input text, identify all "
|
||||||
|
"Personally Identifiable Information (PII), and output the text with the PII seamlessly "
|
||||||
|
"replaced by realistic synthetic data. Maintain the exact original formatting, syntax, "
|
||||||
|
"and tone."
|
||||||
|
)
|
||||||
|
|
||||||
|
TEST_CASES = [
|
||||||
|
("Names", "Dear Mr. Arjun Mehta, your appointment with Dr. Priya Sharma is confirmed for July 15th."),
|
||||||
|
("Emails", "For billing inquiries, contact sarah.johnson@globalfinance.com or accounts@globalfinance.com."),
|
||||||
|
("Phones", "Call our Mumbai office at +91-22-4567-8901 or reach Raj directly on 9876543210."),
|
||||||
|
("Addresses", "Ship the package to 42 Baker Street, London, NW1 6XE, United Kingdom."),
|
||||||
|
("National ID", "Aadhaar verification complete for ID 2345-6789-0123 issued to Neha Gupta."),
|
||||||
|
("Financial", "Payment processed on Visa ending 4829. Transaction ref: TXN-2024-09-17-0042."),
|
||||||
|
("Mixed PII", "Hi, I'm David Chen (david.chen@techcorp.io, +1-415-555-0198). Please update my records."),
|
||||||
|
("Passport", "Passport number L8472910 belonging to Maria Gonzalez expires on 2027-03-22."),
|
||||||
|
("Medical", "Patient: Robert Williams, DOB: 1985-04-12, MRN: MED-2024-88451. Prescribed metformin 500mg."),
|
||||||
|
("Employee", "Employee ID: EMP-30291, Name: Tanaka Yuki, Department: Engineering, SSN: 321-45-6789."),
|
||||||
|
("Informal", "Hey Lisa, it's Mike from the gym. Text me at 555-867-5309 about Saturday's class!"),
|
||||||
|
("Hindi-English", "Ramesh ji ka address hai 14, MG Road, Pune 411001. Unka number 9823456789 hai."),
|
||||||
|
]
|
||||||
|
|
||||||
|
def anonymize(text):
|
||||||
|
messages = [
|
||||||
|
{"role": "system", "content": SYSTEM_PROMPT},
|
||||||
|
{"role": "user", "content": text},
|
||||||
|
]
|
||||||
|
inputs = tokenizer.apply_chat_template(
|
||||||
|
messages, tokenize=True, add_generation_prompt=True, return_tensors="pt"
|
||||||
|
).to(model.device)
|
||||||
|
outputs = model.generate(inputs, max_new_tokens=512, temperature=0.3, top_p=0.9, do_sample=True)
|
||||||
|
return tokenizer.decode(outputs[0][inputs.shape[-1]:], skip_special_tokens=True)
|
||||||
|
|
||||||
|
print("=" * 80)
|
||||||
|
print("PII ANONYMIZER — FULL TEST SUITE")
|
||||||
|
print("=" * 80)
|
||||||
|
|
||||||
|
for i, (category, text) in enumerate(TEST_CASES, 1):
|
||||||
|
result = anonymize(text)
|
||||||
|
print(f"\n── {i}. {category} ──")
|
||||||
|
print(f" INPUT: {text}")
|
||||||
|
print(f" OUTPUT: {result}")
|
||||||
|
|
||||||
|
print("\n" + "=" * 80)
|
||||||
|
print("TEST COMPLETE")
|
||||||
|
print("=" * 80)
|
||||||
|
```
|
||||||
|
|
||||||
|
### With Unsloth (2× Faster Inference, 60% Less Memory)
|
||||||
|
|
||||||
|
```python
|
||||||
|
# pip install "unsloth[colab-new] @ git+https://github.com/unslothai/unsloth.git"
|
||||||
|
|
||||||
|
from unsloth import FastLanguageModel
|
||||||
|
|
||||||
|
model, tokenizer = FastLanguageModel.from_pretrained(
|
||||||
|
model_name="AXONVERTEX-AI-RESEARCH/qwen2.5-0.5b-pii-anonymizer",
|
||||||
|
max_seq_length=2048,
|
||||||
|
dtype=None, # auto-detect
|
||||||
|
load_in_4bit=True, # uses ~1.5GB VRAM
|
||||||
|
)
|
||||||
|
FastLanguageModel.for_inference(model)
|
||||||
|
|
||||||
|
SYSTEM_PROMPT = (
|
||||||
|
"You are an enterprise data privacy engine. Analyze the input text, identify all "
|
||||||
|
"Personally Identifiable Information (PII), and output the text with the PII seamlessly "
|
||||||
|
"replaced by realistic synthetic data. Maintain the exact original formatting, syntax, "
|
||||||
|
"and tone."
|
||||||
|
)
|
||||||
|
|
||||||
|
def anonymize(text):
|
||||||
|
messages = [
|
||||||
|
{"role": "system", "content": SYSTEM_PROMPT},
|
||||||
|
{"role": "user", "content": text},
|
||||||
|
]
|
||||||
|
inputs = tokenizer.apply_chat_template(
|
||||||
|
messages, tokenize=True, add_generation_prompt=True, return_tensors="pt"
|
||||||
|
).to(model.device)
|
||||||
|
outputs = model.generate(inputs, max_new_tokens=512, temperature=0.3, top_p=0.9, do_sample=True)
|
||||||
|
return tokenizer.decode(outputs[0][inputs.shape[-1]:], skip_special_tokens=True)
|
||||||
|
|
||||||
|
print(anonymize("Call Dr. Sarah Chen at +44-20-7946-0958 or email s.chen@hospital.nhs.uk"))
|
||||||
|
```
|
||||||
|
|
||||||
|
### Batch Processing — Anonymize Multiple Documents
|
||||||
|
|
||||||
|
```python
|
||||||
|
from transformers import AutoModelForCausalLM, AutoTokenizer
|
||||||
|
|
||||||
|
MODEL_NAME = "AXONVERTEX-AI-RESEARCH/qwen2.5-0.5b-pii-anonymizer"
|
||||||
|
model = AutoModelForCausalLM.from_pretrained(MODEL_NAME, device_map="auto")
|
||||||
|
tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME)
|
||||||
|
|
||||||
|
SYSTEM_PROMPT = (
|
||||||
|
"You are an enterprise data privacy engine. Analyze the input text, identify all "
|
||||||
|
"Personally Identifiable Information (PII), and output the text with the PII seamlessly "
|
||||||
|
"replaced by realistic synthetic data. Maintain the exact original formatting, syntax, "
|
||||||
|
"and tone."
|
||||||
|
)
|
||||||
|
|
||||||
|
def anonymize(text):
|
||||||
|
messages = [
|
||||||
|
{"role": "system", "content": SYSTEM_PROMPT},
|
||||||
|
{"role": "user", "content": text},
|
||||||
|
]
|
||||||
|
inputs = tokenizer.apply_chat_template(
|
||||||
|
messages, tokenize=True, add_generation_prompt=True, return_tensors="pt"
|
||||||
|
).to(model.device)
|
||||||
|
outputs = model.generate(inputs, max_new_tokens=512, temperature=0.3, top_p=0.9, do_sample=True)
|
||||||
|
return tokenizer.decode(outputs[0][inputs.shape[-1]:], skip_special_tokens=True)
|
||||||
|
|
||||||
|
def anonymize_batch(texts):
|
||||||
|
"""Anonymize a list of texts and return results."""
|
||||||
|
results = []
|
||||||
|
for text in texts:
|
||||||
|
results.append(anonymize(text))
|
||||||
|
return results
|
||||||
|
|
||||||
|
# Example: process a list of customer support tickets
|
||||||
|
tickets = [
|
||||||
|
"Customer Jane Smith (jane.smith@outlook.com) reported billing issue on account #4481-2290.",
|
||||||
|
"Technician Raj Patel visited 15 Elm Street, Apt 3B. Contact: +91-98765-43210.",
|
||||||
|
"Refund processed for order #ORD-2024-1847 to card ending 9012. Customer: Liu Wei.",
|
||||||
|
]
|
||||||
|
|
||||||
|
anonymized = anonymize_batch(tickets)
|
||||||
|
for original, cleaned in zip(tickets, anonymized):
|
||||||
|
print(f"ORIGINAL: {original}")
|
||||||
|
print(f"CLEANED: {cleaned}")
|
||||||
|
print()
|
||||||
|
```
|
||||||
|
|
||||||
|
### Process a File Line-by-Line
|
||||||
|
|
||||||
|
```python
|
||||||
|
from transformers import AutoModelForCausalLM, AutoTokenizer
|
||||||
|
|
||||||
|
MODEL_NAME = "AXONVERTEX-AI-RESEARCH/qwen2.5-0.5b-pii-anonymizer"
|
||||||
|
model = AutoModelForCausalLM.from_pretrained(MODEL_NAME, device_map="auto")
|
||||||
|
tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME)
|
||||||
|
|
||||||
|
SYSTEM_PROMPT = (
|
||||||
|
"You are an enterprise data privacy engine. Analyze the input text, identify all "
|
||||||
|
"Personally Identifiable Information (PII), and output the text with the PII seamlessly "
|
||||||
|
"replaced by realistic synthetic data. Maintain the exact original formatting, syntax, "
|
||||||
|
"and tone."
|
||||||
|
)
|
||||||
|
|
||||||
|
def anonymize(text):
|
||||||
|
messages = [
|
||||||
|
{"role": "system", "content": SYSTEM_PROMPT},
|
||||||
|
{"role": "user", "content": text},
|
||||||
|
]
|
||||||
|
inputs = tokenizer.apply_chat_template(
|
||||||
|
messages, tokenize=True, add_generation_prompt=True, return_tensors="pt"
|
||||||
|
).to(model.device)
|
||||||
|
outputs = model.generate(inputs, max_new_tokens=512, temperature=0.3, top_p=0.9, do_sample=True)
|
||||||
|
return tokenizer.decode(outputs[0][inputs.shape[-1]:], skip_special_tokens=True)
|
||||||
|
|
||||||
|
input_file = "customer_data.txt"
|
||||||
|
output_file = "customer_data_anonymized.txt"
|
||||||
|
|
||||||
|
with open(input_file, "r") as f_in, open(output_file, "w") as f_out:
|
||||||
|
for line_num, line in enumerate(f_in, 1):
|
||||||
|
line = line.strip()
|
||||||
|
if not line:
|
||||||
|
f_out.write("\n")
|
||||||
|
continue
|
||||||
|
cleaned = anonymize(line)
|
||||||
|
f_out.write(cleaned + "\n")
|
||||||
|
if line_num % 10 == 0:
|
||||||
|
print(f"Processed {line_num} lines...")
|
||||||
|
|
||||||
|
print(f"Done. Anonymized output saved to {output_file}")
|
||||||
|
```
|
||||||
|
|
||||||
|
### Integration with Pandas DataFrames
|
||||||
|
|
||||||
|
```python
|
||||||
|
import pandas as pd
|
||||||
|
from transformers import AutoModelForCausalLM, AutoTokenizer
|
||||||
|
from tqdm import tqdm
|
||||||
|
|
||||||
|
MODEL_NAME = "AXONVERTEX-AI-RESEARCH/qwen2.5-0.5b-pii-anonymizer"
|
||||||
|
model = AutoModelForCausalLM.from_pretrained(MODEL_NAME, device_map="auto")
|
||||||
|
tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME)
|
||||||
|
|
||||||
|
SYSTEM_PROMPT = (
|
||||||
|
"You are an enterprise data privacy engine. Analyze the input text, identify all "
|
||||||
|
"Personally Identifiable Information (PII), and output the text with the PII seamlessly "
|
||||||
|
"replaced by realistic synthetic data. Maintain the exact original formatting, syntax, "
|
||||||
|
"and tone."
|
||||||
|
)
|
||||||
|
|
||||||
|
def anonymize(text):
|
||||||
|
if not isinstance(text, str) or not text.strip():
|
||||||
|
return text
|
||||||
|
messages = [
|
||||||
|
{"role": "system", "content": SYSTEM_PROMPT},
|
||||||
|
{"role": "user", "content": text},
|
||||||
|
]
|
||||||
|
inputs = tokenizer.apply_chat_template(
|
||||||
|
messages, tokenize=True, add_generation_prompt=True, return_tensors="pt"
|
||||||
|
).to(model.device)
|
||||||
|
outputs = model.generate(inputs, max_new_tokens=512, temperature=0.3, top_p=0.9, do_sample=True)
|
||||||
|
return tokenizer.decode(outputs[0][inputs.shape[-1]:], skip_special_tokens=True)
|
||||||
|
|
||||||
|
# Load your data
|
||||||
|
df = pd.read_csv("customers.csv")
|
||||||
|
|
||||||
|
# Anonymize specific columns
|
||||||
|
tqdm.pandas(desc="Anonymizing")
|
||||||
|
df["name_clean"] = df["full_name"].progress_apply(anonymize)
|
||||||
|
df["email_clean"] = df["email"].progress_apply(anonymize)
|
||||||
|
df["notes_clean"] = df["support_notes"].progress_apply(anonymize)
|
||||||
|
|
||||||
|
# Save
|
||||||
|
df.to_csv("customers_anonymized.csv", index=False)
|
||||||
|
print(f"Anonymized {len(df)} rows.")
|
||||||
|
```
|
||||||
|
|
||||||
|
### Recommended Generation Parameters
|
||||||
|
|
||||||
|
| Parameter | Value | Why |
|
||||||
|
|-----------|-------|-----|
|
||||||
|
| temperature | 0.3 | Low randomness for consistent PII replacement |
|
||||||
|
| top_p | 0.9 | Nucleus sampling for natural-sounding output |
|
||||||
|
| max_new_tokens | 512 | Sufficient for most document chunks |
|
||||||
|
| do_sample | True | Required for temperature/top_p to take effect |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Known Limitations
|
||||||
|
|
||||||
|
This is a Phase 1 model. Honest assessment of current limitations:
|
||||||
|
|
||||||
|
1. **Occasional artifact tokens**: Rare garbage tokens (e.g., "xQZo") can appear before synthetic names. Occurs in <5% of outputs.
|
||||||
|
2. **Over-replacement**: Sometimes replaces non-PII context (e.g., "Mumbai" → "Port Michaelborough", "Engineering" → "Engineer, technical sales"). The model can be too aggressive.
|
||||||
|
3. **Format-unaware replacements**: Aadhaar numbers replaced with non-numeric strings, postal codes with random characters. The model doesn't always respect the format constraints of specific ID types.
|
||||||
|
4. **Missed PII**: Card endings ("4829"), MRN numbers, and some phone numbers in Hindi-English text were not replaced.
|
||||||
|
5. **English-primary**: While the training data includes French, German, and Italian text, the model performs best on English. Multilingual coverage is inconsistent.
|
||||||
|
6. **No deterministic guarantees**: As a generative model, outputs can vary between runs. Not suitable as a sole compliance mechanism.
|
||||||
|
|
||||||
|
These limitations are precisely why Phase 2 adds Presidio as a pre/post-processing safety net.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Phase 2 Roadmap
|
||||||
|
|
||||||
|
Phase 2 wraps this model in a production-ready serving architecture:
|
||||||
|
|
||||||
|
```
|
||||||
|
[Raw Text Input]
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
[Microsoft Presidio Analyzer] → Detect PII with high-precision rules
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
[GLiNER NER Model] → Catch contextual PII that rules miss
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
[This Fine-Tuned Model] → Generate natural synthetic replacements
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
[Presidio Analyzer (2nd pass)] → Verify no PII leaked through
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
[Clean Output via FastAPI]
|
||||||
|
```
|
||||||
|
|
||||||
|
- Presidio handles the "don't miss anything" job (structured PII: SSNs, credit cards, IBANs)
|
||||||
|
- GLiNER handles contextual entity recognition
|
||||||
|
- This model handles the "make it read naturally" job
|
||||||
|
- The second Presidio pass acts as a compliance safety net
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
This model is released under a **composite license** reflecting the licenses of all components used in training. See [LICENSE.md](LICENSE.md) for complete terms.
|
||||||
|
|
||||||
|
| Component | License | Commercial Use |
|
||||||
|
|-----------|---------|----------------|
|
||||||
|
| Qwen2.5-0.5B-Instruct (base model) | Apache 2.0 | Yes |
|
||||||
|
| nvidia/Nemotron-PII (dataset) | CC-BY-4.0 | Yes, with attribution |
|
||||||
|
| ai4privacy/pii-masking-200k (dataset) | AI4Privacy Free/Corporate License | Free for individuals and small businesses (≤3 employees). Larger organizations require a corporate license from licensing@ai4privacy.com |
|
||||||
|
| Unsloth (training framework) | Apache 2.0 | Yes |
|
||||||
|
| Model weights (this repository) | Subject to the most restrictive upstream license | See LICENSE.md |
|
||||||
|
|
||||||
|
**Important**: If you are a commercial entity with more than 3 employees, you must obtain a corporate license from AI4Privacy before using this model in production. Contact licensing@ai4privacy.com.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Citation
|
||||||
|
|
||||||
|
If you use this model in your research or products, please cite:
|
||||||
|
|
||||||
|
```bibtex
|
||||||
|
@misc{qwen25-pii-anonymizer-2025,
|
||||||
|
title={Qwen2.5-0.5B PII Anonymizer: Context-Aware Synthetic PII Rewriting via QLoRA},
|
||||||
|
year={2025},
|
||||||
|
publisher={HuggingFace},
|
||||||
|
url={https://huggingface.co/AXONVERTEX-AI-RESEARCH/qwen2.5-0.5b-pii-anonymizer}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Please also cite the upstream datasets:
|
||||||
|
|
||||||
|
```bibtex
|
||||||
|
@dataset{nvidia_nemotron_pii_2024,
|
||||||
|
title={Nemotron-PII: Synthetic Persona-Grounded PII/PHI Detection Dataset},
|
||||||
|
author={NVIDIA},
|
||||||
|
year={2024},
|
||||||
|
publisher={HuggingFace},
|
||||||
|
url={https://huggingface.co/datasets/nvidia/Nemotron-PII},
|
||||||
|
license={CC-BY-4.0}
|
||||||
|
}
|
||||||
|
|
||||||
|
@dataset{ai4privacy_pii_masking_200k_2023,
|
||||||
|
title={PII Masking 200K Dataset},
|
||||||
|
author={AI4Privacy (Ai Suisse SA)},
|
||||||
|
year={2023},
|
||||||
|
publisher={HuggingFace},
|
||||||
|
doi={10.57967/hf/1532},
|
||||||
|
url={https://huggingface.co/datasets/ai4privacy/pii-masking-200k}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Acknowledgments
|
||||||
|
|
||||||
|
- **[Qwen Team (Alibaba Cloud)](https://github.com/QwenLM)** for the Qwen2.5 base model family
|
||||||
|
- **[NVIDIA](https://huggingface.co/nvidia)** for the Nemotron-PII dataset and NeMo Data Designer
|
||||||
|
- **[AI4Privacy (Ai Suisse SA)](https://huggingface.co/ai4privacy)** for the PII Masking 200K dataset
|
||||||
|
- **[Unsloth](https://github.com/unslothai/unsloth)** for the optimized QLoRA training framework
|
||||||
|
- **[Faker](https://faker.readthedocs.io/)** for synthetic data generation during data engineering
|
||||||
|
- **[HuggingFace](https://huggingface.co)** for the Transformers, TRL, and Datasets libraries
|
||||||
54
chat_template.jinja
Normal file
54
chat_template.jinja
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
{%- if tools %}
|
||||||
|
{{- '<|im_start|>system\n' }}
|
||||||
|
{%- if messages[0]['role'] == 'system' %}
|
||||||
|
{{- messages[0]['content'] }}
|
||||||
|
{%- else %}
|
||||||
|
{{- 'You are Qwen, created by Alibaba Cloud. You are a helpful assistant.' }}
|
||||||
|
{%- endif %}
|
||||||
|
{{- "\n\n# Tools\n\nYou may call one or more functions to assist with the user query.\n\nYou are provided with function signatures within <tools></tools> XML tags:\n<tools>" }}
|
||||||
|
{%- for tool in tools %}
|
||||||
|
{{- "\n" }}
|
||||||
|
{{- tool | tojson }}
|
||||||
|
{%- endfor %}
|
||||||
|
{{- "\n</tools>\n\nFor each function call, return a json object with function name and arguments within <tool_call></tool_call> XML tags:\n<tool_call>\n{\"name\": <function-name>, \"arguments\": <args-json-object>}\n</tool_call><|im_end|>\n" }}
|
||||||
|
{%- else %}
|
||||||
|
{%- if messages[0]['role'] == 'system' %}
|
||||||
|
{{- '<|im_start|>system\n' + messages[0]['content'] + '<|im_end|>\n' }}
|
||||||
|
{%- else %}
|
||||||
|
{{- '<|im_start|>system\nYou are Qwen, created by Alibaba Cloud. You are a helpful assistant.<|im_end|>\n' }}
|
||||||
|
{%- endif %}
|
||||||
|
{%- endif %}
|
||||||
|
{%- for message in messages %}
|
||||||
|
{%- if (message.role == "user") or (message.role == "system" and not loop.first) or (message.role == "assistant" and not message.tool_calls) %}
|
||||||
|
{{- '<|im_start|>' + message.role + '\n' + message.content + '<|im_end|>' + '\n' }}
|
||||||
|
{%- elif message.role == "assistant" %}
|
||||||
|
{{- '<|im_start|>' + message.role }}
|
||||||
|
{%- if message.content %}
|
||||||
|
{{- '\n' + message.content }}
|
||||||
|
{%- endif %}
|
||||||
|
{%- for tool_call in message.tool_calls %}
|
||||||
|
{%- if tool_call.function is defined %}
|
||||||
|
{%- set tool_call = tool_call.function %}
|
||||||
|
{%- endif %}
|
||||||
|
{{- '\n<tool_call>\n{"name": "' }}
|
||||||
|
{{- tool_call.name }}
|
||||||
|
{{- '", "arguments": ' }}
|
||||||
|
{{- tool_call.arguments | tojson }}
|
||||||
|
{{- '}\n</tool_call>' }}
|
||||||
|
{%- endfor %}
|
||||||
|
{{- '<|im_end|>\n' }}
|
||||||
|
{%- elif message.role == "tool" %}
|
||||||
|
{%- if (loop.index0 == 0) or (messages[loop.index0 - 1].role != "tool") %}
|
||||||
|
{{- '<|im_start|>user' }}
|
||||||
|
{%- endif %}
|
||||||
|
{{- '\n<tool_response>\n' }}
|
||||||
|
{{- message.content }}
|
||||||
|
{{- '\n</tool_response>' }}
|
||||||
|
{%- if loop.last or (messages[loop.index0 + 1].role != "tool") %}
|
||||||
|
{{- '<|im_end|>\n' }}
|
||||||
|
{%- endif %}
|
||||||
|
{%- endif %}
|
||||||
|
{%- endfor %}
|
||||||
|
{%- if add_generation_prompt %}
|
||||||
|
{{- '<|im_start|>assistant\n' }}
|
||||||
|
{%- endif %}
|
||||||
58
config.json
Normal file
58
config.json
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
{
|
||||||
|
"architectures": [
|
||||||
|
"Qwen2ForCausalLM"
|
||||||
|
],
|
||||||
|
"attention_dropout": 0.0,
|
||||||
|
"bos_token_id": null,
|
||||||
|
"torch_dtype": "bfloat16",
|
||||||
|
"eos_token_id": 151645,
|
||||||
|
"hidden_act": "silu",
|
||||||
|
"hidden_size": 896,
|
||||||
|
"initializer_range": 0.02,
|
||||||
|
"intermediate_size": 4864,
|
||||||
|
"layer_types": [
|
||||||
|
"full_attention",
|
||||||
|
"full_attention",
|
||||||
|
"full_attention",
|
||||||
|
"full_attention",
|
||||||
|
"full_attention",
|
||||||
|
"full_attention",
|
||||||
|
"full_attention",
|
||||||
|
"full_attention",
|
||||||
|
"full_attention",
|
||||||
|
"full_attention",
|
||||||
|
"full_attention",
|
||||||
|
"full_attention",
|
||||||
|
"full_attention",
|
||||||
|
"full_attention",
|
||||||
|
"full_attention",
|
||||||
|
"full_attention",
|
||||||
|
"full_attention",
|
||||||
|
"full_attention",
|
||||||
|
"full_attention",
|
||||||
|
"full_attention",
|
||||||
|
"full_attention",
|
||||||
|
"full_attention",
|
||||||
|
"full_attention",
|
||||||
|
"full_attention"
|
||||||
|
],
|
||||||
|
"max_position_embeddings": 32768,
|
||||||
|
"max_window_layers": 21,
|
||||||
|
"model_type": "qwen2",
|
||||||
|
"num_attention_heads": 14,
|
||||||
|
"num_hidden_layers": 24,
|
||||||
|
"num_key_value_heads": 2,
|
||||||
|
"pad_token_id": 151645,
|
||||||
|
"rms_norm_eps": 1e-06,
|
||||||
|
"rope_parameters": {
|
||||||
|
"rope_theta": 1000000.0,
|
||||||
|
"rope_type": "default"
|
||||||
|
},
|
||||||
|
"sliding_window": null,
|
||||||
|
"tie_word_embeddings": true,
|
||||||
|
"unsloth_fixed": true,
|
||||||
|
"unsloth_version": "2026.6.3",
|
||||||
|
"use_cache": true,
|
||||||
|
"use_sliding_window": false,
|
||||||
|
"vocab_size": 151936
|
||||||
|
}
|
||||||
14
generation_config.json
Normal file
14
generation_config.json
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"do_sample": true,
|
||||||
|
"eos_token_id": [
|
||||||
|
151645,
|
||||||
|
151643
|
||||||
|
],
|
||||||
|
"max_length": 32768,
|
||||||
|
"pad_token_id": 151645,
|
||||||
|
"repetition_penalty": 1.1,
|
||||||
|
"temperature": 0.7,
|
||||||
|
"top_k": 20,
|
||||||
|
"top_p": 0.8,
|
||||||
|
"transformers_version": "5.5.0"
|
||||||
|
}
|
||||||
3
model.safetensors
Normal file
3
model.safetensors
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:8de3e97ee24f653d9731a6ba0a5adbdad70c4be4c8bee0c3ae7b9e2abc02af0b
|
||||||
|
size 988097824
|
||||||
3
tokenizer.json
Normal file
3
tokenizer.json
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:bd5948af71b4f56cf697f7580814c7ce8b80595ef985544efcacf716126a2e31
|
||||||
|
size 11422356
|
||||||
202
tokenizer_config.json
Normal file
202
tokenizer_config.json
Normal file
@@ -0,0 +1,202 @@
|
|||||||
|
{
|
||||||
|
"add_prefix_space": false,
|
||||||
|
"backend": "tokenizers",
|
||||||
|
"bos_token": null,
|
||||||
|
"clean_up_tokenization_spaces": false,
|
||||||
|
"eos_token": "<|im_end|>",
|
||||||
|
"errors": "replace",
|
||||||
|
"is_local": false,
|
||||||
|
"model_max_length": 32768,
|
||||||
|
"pad_token": "<|im_end|>",
|
||||||
|
"padding_side": "left",
|
||||||
|
"split_special_tokens": false,
|
||||||
|
"tokenizer_class": "Qwen2Tokenizer",
|
||||||
|
"unk_token": null,
|
||||||
|
"added_tokens_decoder": {
|
||||||
|
"151643": {
|
||||||
|
"content": "<|endoftext|>",
|
||||||
|
"single_word": false,
|
||||||
|
"lstrip": false,
|
||||||
|
"rstrip": false,
|
||||||
|
"normalized": false,
|
||||||
|
"special": true
|
||||||
|
},
|
||||||
|
"151644": {
|
||||||
|
"content": "<|im_start|>",
|
||||||
|
"single_word": false,
|
||||||
|
"lstrip": false,
|
||||||
|
"rstrip": false,
|
||||||
|
"normalized": false,
|
||||||
|
"special": true
|
||||||
|
},
|
||||||
|
"151645": {
|
||||||
|
"content": "<|im_end|>",
|
||||||
|
"single_word": false,
|
||||||
|
"lstrip": false,
|
||||||
|
"rstrip": false,
|
||||||
|
"normalized": false,
|
||||||
|
"special": true
|
||||||
|
},
|
||||||
|
"151646": {
|
||||||
|
"content": "<|object_ref_start|>",
|
||||||
|
"single_word": false,
|
||||||
|
"lstrip": false,
|
||||||
|
"rstrip": false,
|
||||||
|
"normalized": false,
|
||||||
|
"special": true
|
||||||
|
},
|
||||||
|
"151647": {
|
||||||
|
"content": "<|object_ref_end|>",
|
||||||
|
"single_word": false,
|
||||||
|
"lstrip": false,
|
||||||
|
"rstrip": false,
|
||||||
|
"normalized": false,
|
||||||
|
"special": true
|
||||||
|
},
|
||||||
|
"151648": {
|
||||||
|
"content": "<|box_start|>",
|
||||||
|
"single_word": false,
|
||||||
|
"lstrip": false,
|
||||||
|
"rstrip": false,
|
||||||
|
"normalized": false,
|
||||||
|
"special": true
|
||||||
|
},
|
||||||
|
"151649": {
|
||||||
|
"content": "<|box_end|>",
|
||||||
|
"single_word": false,
|
||||||
|
"lstrip": false,
|
||||||
|
"rstrip": false,
|
||||||
|
"normalized": false,
|
||||||
|
"special": true
|
||||||
|
},
|
||||||
|
"151650": {
|
||||||
|
"content": "<|quad_start|>",
|
||||||
|
"single_word": false,
|
||||||
|
"lstrip": false,
|
||||||
|
"rstrip": false,
|
||||||
|
"normalized": false,
|
||||||
|
"special": true
|
||||||
|
},
|
||||||
|
"151651": {
|
||||||
|
"content": "<|quad_end|>",
|
||||||
|
"single_word": false,
|
||||||
|
"lstrip": false,
|
||||||
|
"rstrip": false,
|
||||||
|
"normalized": false,
|
||||||
|
"special": true
|
||||||
|
},
|
||||||
|
"151652": {
|
||||||
|
"content": "<|vision_start|>",
|
||||||
|
"single_word": false,
|
||||||
|
"lstrip": false,
|
||||||
|
"rstrip": false,
|
||||||
|
"normalized": false,
|
||||||
|
"special": true
|
||||||
|
},
|
||||||
|
"151653": {
|
||||||
|
"content": "<|vision_end|>",
|
||||||
|
"single_word": false,
|
||||||
|
"lstrip": false,
|
||||||
|
"rstrip": false,
|
||||||
|
"normalized": false,
|
||||||
|
"special": true
|
||||||
|
},
|
||||||
|
"151654": {
|
||||||
|
"content": "<|vision_pad|>",
|
||||||
|
"single_word": false,
|
||||||
|
"lstrip": false,
|
||||||
|
"rstrip": false,
|
||||||
|
"normalized": false,
|
||||||
|
"special": true
|
||||||
|
},
|
||||||
|
"151655": {
|
||||||
|
"content": "<|image_pad|>",
|
||||||
|
"single_word": false,
|
||||||
|
"lstrip": false,
|
||||||
|
"rstrip": false,
|
||||||
|
"normalized": false,
|
||||||
|
"special": true
|
||||||
|
},
|
||||||
|
"151656": {
|
||||||
|
"content": "<|video_pad|>",
|
||||||
|
"single_word": false,
|
||||||
|
"lstrip": false,
|
||||||
|
"rstrip": false,
|
||||||
|
"normalized": false,
|
||||||
|
"special": true
|
||||||
|
},
|
||||||
|
"151657": {
|
||||||
|
"content": "<tool_call>",
|
||||||
|
"single_word": false,
|
||||||
|
"lstrip": false,
|
||||||
|
"rstrip": false,
|
||||||
|
"normalized": false,
|
||||||
|
"special": false
|
||||||
|
},
|
||||||
|
"151658": {
|
||||||
|
"content": "</tool_call>",
|
||||||
|
"single_word": false,
|
||||||
|
"lstrip": false,
|
||||||
|
"rstrip": false,
|
||||||
|
"normalized": false,
|
||||||
|
"special": false
|
||||||
|
},
|
||||||
|
"151659": {
|
||||||
|
"content": "<|fim_prefix|>",
|
||||||
|
"single_word": false,
|
||||||
|
"lstrip": false,
|
||||||
|
"rstrip": false,
|
||||||
|
"normalized": false,
|
||||||
|
"special": false
|
||||||
|
},
|
||||||
|
"151660": {
|
||||||
|
"content": "<|fim_middle|>",
|
||||||
|
"single_word": false,
|
||||||
|
"lstrip": false,
|
||||||
|
"rstrip": false,
|
||||||
|
"normalized": false,
|
||||||
|
"special": false
|
||||||
|
},
|
||||||
|
"151661": {
|
||||||
|
"content": "<|fim_suffix|>",
|
||||||
|
"single_word": false,
|
||||||
|
"lstrip": false,
|
||||||
|
"rstrip": false,
|
||||||
|
"normalized": false,
|
||||||
|
"special": false
|
||||||
|
},
|
||||||
|
"151662": {
|
||||||
|
"content": "<|fim_pad|>",
|
||||||
|
"single_word": false,
|
||||||
|
"lstrip": false,
|
||||||
|
"rstrip": false,
|
||||||
|
"normalized": false,
|
||||||
|
"special": false
|
||||||
|
},
|
||||||
|
"151663": {
|
||||||
|
"content": "<|repo_name|>",
|
||||||
|
"single_word": false,
|
||||||
|
"lstrip": false,
|
||||||
|
"rstrip": false,
|
||||||
|
"normalized": false,
|
||||||
|
"special": false
|
||||||
|
},
|
||||||
|
"151664": {
|
||||||
|
"content": "<|file_sep|>",
|
||||||
|
"single_word": false,
|
||||||
|
"lstrip": false,
|
||||||
|
"rstrip": false,
|
||||||
|
"normalized": false,
|
||||||
|
"special": false
|
||||||
|
},
|
||||||
|
"151665": {
|
||||||
|
"content": "<|PAD_TOKEN|>",
|
||||||
|
"single_word": false,
|
||||||
|
"lstrip": false,
|
||||||
|
"rstrip": false,
|
||||||
|
"normalized": false,
|
||||||
|
"special": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"chat_template": "{%- if tools %}\n {{- '<|im_start|>system\\n' }}\n {%- if messages[0]['role'] == 'system' %}\n {{- messages[0]['content'] }}\n {%- else %}\n {{- 'You are Qwen, created by Alibaba Cloud. You are a helpful assistant.' }}\n {%- endif %}\n {{- \"\\n\\n# Tools\\n\\nYou may call one or more functions to assist with the user query.\\n\\nYou are provided with function signatures within <tools></tools> XML tags:\\n<tools>\" }}\n {%- for tool in tools %}\n {{- \"\\n\" }}\n {{- tool | tojson }}\n {%- endfor %}\n {{- \"\\n</tools>\\n\\nFor each function call, return a json object with function name and arguments within <tool_call></tool_call> XML tags:\\n<tool_call>\\n{\\\"name\\\": <function-name>, \\\"arguments\\\": <args-json-object>}\\n</tool_call><|im_end|>\\n\" }}\n{%- else %}\n {%- if messages[0]['role'] == 'system' %}\n {{- '<|im_start|>system\\n' + messages[0]['content'] + '<|im_end|>\\n' }}\n {%- else %}\n {{- '<|im_start|>system\\nYou are Qwen, created by Alibaba Cloud. You are a helpful assistant.<|im_end|>\\n' }}\n {%- endif %}\n{%- endif %}\n{%- for message in messages %}\n {%- if (message.role == \"user\") or (message.role == \"system\" and not loop.first) or (message.role == \"assistant\" and not message.tool_calls) %}\n {{- '<|im_start|>' + message.role + '\\n' + message.content + '<|im_end|>' + '\\n' }}\n {%- elif message.role == \"assistant\" %}\n {{- '<|im_start|>' + message.role }}\n {%- if message.content %}\n {{- '\\n' + message.content }}\n {%- endif %}\n {%- for tool_call in message.tool_calls %}\n {%- if tool_call.function is defined %}\n {%- set tool_call = tool_call.function %}\n {%- endif %}\n {{- '\\n<tool_call>\\n{\"name\": \"' }}\n {{- tool_call.name }}\n {{- '\", \"arguments\": ' }}\n {{- tool_call.arguments | tojson }}\n {{- '}\\n</tool_call>' }}\n {%- endfor %}\n {{- '<|im_end|>\\n' }}\n {%- elif message.role == \"tool\" %}\n {%- if (loop.index0 == 0) or (messages[loop.index0 - 1].role != \"tool\") %}\n {{- '<|im_start|>user' }}\n {%- endif %}\n {{- '\\n<tool_response>\\n' }}\n {{- message.content }}\n {{- '\\n</tool_response>' }}\n {%- if loop.last or (messages[loop.index0 + 1].role != \"tool\") %}\n {{- '<|im_end|>\\n' }}\n {%- endif %}\n {%- endif %}\n{%- endfor %}\n{%- if add_generation_prompt %}\n {{- '<|im_start|>assistant\\n' }}\n{%- endif %}\n"
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user